mirror of
https://github.com/YunoHost/apps.git
synced 2024-09-03 20:06:07 +02:00
Misc dashboard enhancement (#2365)
* store/dash: store by popularity by default * store/dash: add 'last update X hours ago' info at the bottom * store/dash: misc responsiveness improvements
This commit is contained in:
parent
298f04dcb8
commit
32fd827795
2 changed files with 52 additions and 36 deletions
15
store/app.py
15
store/app.py
|
@ -91,6 +91,14 @@ def days_ago(timestamp):
|
||||||
return int((time.time() - timestamp) / (60 * 60 * 24))
|
return int((time.time() - timestamp) / (60 * 60 * 24))
|
||||||
|
|
||||||
|
|
||||||
|
@app.template_filter("hours_ago")
|
||||||
|
def hours_ago(timestamp):
|
||||||
|
d = datetime.now() - datetime.fromtimestamp(timestamp)
|
||||||
|
hours = int(divmod(d.total_seconds(), 3600)[0])
|
||||||
|
minutes = int(divmod(d.total_seconds(), 60)[1])
|
||||||
|
return f"{hours}:{minutes}h"
|
||||||
|
|
||||||
|
|
||||||
@app.template_filter("format_datetime")
|
@app.template_filter("format_datetime")
|
||||||
def format_datetime(value, format="%d %b %Y %I:%M %p"):
|
def format_datetime(value, format="%d %b %Y %I:%M %p"):
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -464,7 +472,12 @@ Description: {description}
|
||||||
|
|
||||||
@app.route("/dash")
|
@app.route("/dash")
|
||||||
def dash():
|
def dash():
|
||||||
return render_template("dash.html", data=get_dashboard_data(), stars=get_stars())
|
|
||||||
|
# Sort by popularity by default
|
||||||
|
stars = get_stars()
|
||||||
|
data = dict(sorted(get_dashboard_data().items(), key=lambda app: len(stars.get(app[0], [])), reverse=True))
|
||||||
|
|
||||||
|
return render_template("dash.html", data=data, stars=stars, last_data_update=get_dashboard_data.mtime)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/charts")
|
@app.route("/charts")
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
<h1 class="text-2xl font-bold">
|
<h1 class="text-2xl font-bold">
|
||||||
{{ _("App packaging dashboard") }}
|
{{ _("App packaging dashboard") }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-sm text-gray-700 mx-10 mt-2">{{ _("This is where packagers can monitor the status of automatic tests (CI) and ongoing major pull requests accross all apps. If you want to get started with app packaging in YunoHost, please check out the <a class='text-blue-500' href='https://yunohost.org/packaging_apps'>packaging documentation</a> and come say hi to us on the <a class='text-blue-500' href='https://yunohost.org/chat_rooms'>app packaging chatroom</a>!") }}</p>
|
<p class="text-sm text-gray-700 mx-2 md:mx-32 mt-2">{{ _("This is where packagers can monitor the status of automatic tests (CI) and ongoing major pull requests accross all apps. If you want to get started with app packaging in YunoHost, please check out the <a class='text-blue-500' href='https://yunohost.org/packaging_apps'>packaging documentation</a> and come say hi to us on the <a class='text-blue-500' href='https://yunohost.org/chat_rooms'>app packaging chatroom</a>!") }}</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mx-auto text-center py-4">
|
|
||||||
<div class="inline-block w-5/12">
|
<div class="mx-auto text-center space-y-3 md:space-y-0 md:space-x-3 px-2 md:px-10 lg:px-20 flex flex-col md:flex-row items-center">
|
||||||
|
<div class="inline-block basis-1/2">
|
||||||
{{ _("Filter") }}
|
{{ _("Filter") }}
|
||||||
<select
|
<select
|
||||||
name="selectfilter"
|
name="selectfilter"
|
||||||
|
@ -30,20 +31,21 @@
|
||||||
<option {% if request.args.get("filter") == "packagingv1" %}selected{% endif %} value="packagingv1">{{ _("Packaging v1 apps") }}</option>
|
<option {% if request.args.get("filter") == "packagingv1" %}selected{% endif %} value="packagingv1">{{ _("Packaging v1 apps") }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-block w-5/12">
|
<div class="inline-block basis-1/2">
|
||||||
{{ _("Sort by") }}
|
{{ _("Sort by") }}
|
||||||
<select
|
<select
|
||||||
name="selectsort"
|
name="selectsort"
|
||||||
id="selectsort"
|
id="selectsort"
|
||||||
class="rounded-md border-gray-200 text-sm h-8 py-0"
|
class="rounded-md border-gray-200 text-sm h-8 py-0"
|
||||||
>
|
>
|
||||||
<option {% if request.args.get("sort") in [None, "alpha"] %}selected{% endif %} value="alpha">{{ _("Alphabetical") }}</option>
|
<option {% if request.args.get("sort") == "alpha" %}selected{% endif %} value="alpha">{{ _("Alphabetical") }}</option>
|
||||||
<option {% if request.args.get("sort") == "level" %}selected{% endif %} value="level">{{ _("Quality level") }}</option>
|
<option {% if request.args.get("sort") == "level" %}selected{% endif %} value="level">{{ _("Quality level") }}</option>
|
||||||
<option {% if request.args.get("sort") == "stars" %}selected{% endif %} value="stars">{{ _("Popularity stars") }}</option>
|
<option {% if request.args.get("sort") in [None, "stars"] %}selected{% endif %} value="stars">{{ _("Popularity stars") }}</option>
|
||||||
<option {% if request.args.get("sort") == "main_branch_update" %}selected{% endif %} value="main_branch_update">{{ _("Last update on main/master branch") }}</option>
|
<option {% if request.args.get("sort") == "main_branch_update" %}selected{% endif %} value="main_branch_update">{{ _("Last update on main/master branch") }}</option>
|
||||||
<option {% if request.args.get("sort") == "testing_branch_update" %}selected{% endif %} value="testing_branch_update">{{ _("Last update on testing branch") }}</option>
|
<option {% if request.args.get("sort") == "testing_branch_update" %}selected{% endif %} value="testing_branch_update">{{ _("Last update on testing branch") }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="block w-fit mx-auto flex items-center px-2 pt-2 {% if not user %}text-gray-500{% endif %}" {% if not user %}title="{{ _('Requires to be logged-in') }}" aria-label="{{ _('Requires to be logged-in') }}"{% endif %}>
|
<div class="block w-fit mx-auto flex items-center px-2 pt-2 {% if not user %}text-gray-500{% endif %}" {% if not user %}title="{{ _('Requires to be logged-in') }}" aria-label="{{ _('Requires to be logged-in') }}"{% endif %}>
|
||||||
<label for="starsonly" class="inline-block relative mr-2 h-4 w-7 cursor-pointer">
|
<label for="starsonly" class="inline-block relative mr-2 h-4 w-7 cursor-pointer">
|
||||||
<span class="sr-only">{{ _("Show only apps you starred") }}</span>
|
<span class="sr-only">{{ _("Show only apps you starred") }}</span>
|
||||||
|
@ -58,11 +60,9 @@
|
||||||
{{ _("Show only apps you starred") }}
|
{{ _("Show only apps you starred") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<table id="appTable" class="mx-auto text-sm sm:text-base">
|
||||||
|
|
||||||
<table id="appTable" class="mx-auto">
|
|
||||||
<tr class="h-40 md:h-20">
|
<tr class="h-40 md:h-20">
|
||||||
<th class="max-w-20 md:max-w-32">{{ _("App") }}</th>
|
<th class="max-w-24 md:max-w-32">{{ _("App") }}</th>
|
||||||
<th class="-rotate-90 md:-rotate-45 max-w-10 md:max-w-16 text-left text-nowrap">{{ _("Catalog") }}</th>
|
<th class="-rotate-90 md:-rotate-45 max-w-10 md:max-w-16 text-left text-nowrap">{{ _("Catalog") }}</th>
|
||||||
<th class="-rotate-90 md:-rotate-45 max-w-10 md:max-w-16 text-left text-nowrap">{{ _("Main CI") }}</th>
|
<th class="-rotate-90 md:-rotate-45 max-w-10 md:max-w-16 text-left text-nowrap">{{ _("Main CI") }}</th>
|
||||||
<th class="-rotate-90 md:-rotate-45 max-w-10 md:max-w-16 text-left text-nowrap">{{ _("Bookworm CI") }}</th>
|
<th class="-rotate-90 md:-rotate-45 max-w-10 md:max-w-16 text-left text-nowrap">{{ _("Bookworm CI") }}</th>
|
||||||
|
@ -88,13 +88,15 @@
|
||||||
data-main-ci-level="{% if infos["ci_results"]["main"] %}{{ infos["ci_results"]["main"]["level"] }}{% else %}-1{% endif %}"
|
data-main-ci-level="{% if infos["ci_results"]["main"] %}{{ infos["ci_results"]["main"]["level"] }}{% else %}-1{% endif %}"
|
||||||
data-main-ci-daysago="{% if infos["ci_results"]["main"] %}{{ infos["ci_results"]["main"]["timestamp"] | days_ago }}{% else %}-9999{% endif %}"
|
data-main-ci-daysago="{% if infos["ci_results"]["main"] %}{{ infos["ci_results"]["main"]["timestamp"] | days_ago }}{% else %}-9999{% endif %}"
|
||||||
data-nextdebian-ci-level="{% if infos["ci_results"]["nextdebian"] %}{{ infos["ci_results"]["nextdebian"]["level"] }}{% else %}-1{% endif %}"
|
data-nextdebian-ci-level="{% if infos["ci_results"]["nextdebian"] %}{{ infos["ci_results"]["nextdebian"]["level"] }}{% else %}-1{% endif %}"
|
||||||
data-last-update-master-daysago="{{ infos["ci_results"]["main"]["timestamp"] | days_ago }}"
|
data-last-update-master="{{ infos["ci_results"]["main"]["timestamp"] }}"
|
||||||
data-last-update-testing-daysago="{% if infos["testing"] %}{{ infos["testing"]["timestamp_updated"] | days_ago }}{% endif %}"
|
data-last-update-testing="{% if infos["testing"] %}{{ infos["testing"]["timestamp_updated"] }}{% else %}-1{% endif %}"
|
||||||
data-last-update-autoupdate-daysago="{% if infos["ci-auto-update"] %}{{ infos["ci-auto-update"]["timestamp_updated"] | days_ago }}{% endif %}"
|
data-last-update-autoupdate="{% if infos["ci-auto-update"] %}{{ infos["ci-auto-update"]["timestamp_updated"] }}{% else %}-1{% endif %}"
|
||||||
data-packaging-format="{{ infos["packaging_format"] }}"
|
data-packaging-format="{{ infos["packaging_format"] }}"
|
||||||
>
|
>
|
||||||
<td class="max-w-40 md:max-w-64 text-center text-blue-600 font-medium"><a href="{{ infos["url"] }}">{{ app }}</a></td>
|
<td class="truncate max-w-24 md:max-w-64 text-center text-blue-600 font-medium">
|
||||||
<td class="font-bold">
|
<a href="{{ infos["url"] }}">{{ app }}</a>
|
||||||
|
</td>
|
||||||
|
<td class="font-bold text-center">
|
||||||
<a href="{{ url_for('app_info', app_id=app) }}">
|
<a href="{{ url_for('app_info', app_id=app) }}">
|
||||||
{{ infos["public_level"] }}
|
{{ infos["public_level"] }}
|
||||||
{% if infos["public_level"] == "?" %}
|
{% if infos["public_level"] == "?" %}
|
||||||
|
@ -105,7 +107,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="border-l-2 border-gray-100 text-center">
|
||||||
<a class="{% if infos["public_level"] == infos["ci_results"]["main"]["level"] or infos["ci_results"]["main"]["timestamp"] | days_ago > 30 %}opacity-50{% endif %}" href="https://ci-apps.yunohost.org/ci/apps/{{ app }}/">
|
<a class="{% if infos["public_level"] == infos["ci_results"]["main"]["level"] or infos["ci_results"]["main"]["timestamp"] | days_ago > 30 %}opacity-50{% endif %}" href="https://ci-apps.yunohost.org/ci/apps/{{ app }}/">
|
||||||
{% if infos["public_level"] == infos["ci_results"]["main"]["level"] %}
|
{% if infos["public_level"] == infos["ci_results"]["main"]["level"] %}
|
||||||
=
|
=
|
||||||
|
@ -123,7 +125,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="text-center">
|
||||||
<a class="{% if infos["ci_results"]["nextdebian"] and ((infos["public_level"] == infos["ci_results"]["nextdebian"]["level"]) or (infos["ci_results"]["nextdebian"]["timestamp"] | days_ago) > 30) %}opacity-50{% endif %}" href="https://ci-apps-bookworm.yunohost.org/ci/apps/{{ app }}/">
|
<a class="{% if infos["ci_results"]["nextdebian"] and ((infos["public_level"] == infos["ci_results"]["nextdebian"]["level"]) or (infos["ci_results"]["nextdebian"]["timestamp"] | days_ago) > 30) %}opacity-50{% endif %}" href="https://ci-apps-bookworm.yunohost.org/ci/apps/{{ app }}/">
|
||||||
{% if infos["ci_results"]["nextdebian"] %}
|
{% if infos["ci_results"]["nextdebian"] %}
|
||||||
{% if infos["public_level"] == infos["ci_results"]["nextdebian"]["level"] %}
|
{% if infos["public_level"] == infos["ci_results"]["nextdebian"]["level"] %}
|
||||||
|
@ -145,7 +147,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="border-l-2 border-gray-100 text-center">
|
||||||
{% if "testing" in infos %}
|
{% if "testing" in infos %}
|
||||||
<a href="{{ infos["testing"]["url"] }}">
|
<a href="{{ infos["testing"]["url"] }}">
|
||||||
<i class="fa fa-flask"></i>
|
<i class="fa fa-flask"></i>
|
||||||
|
@ -160,7 +162,7 @@
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="border-r-2 border-gray-100 text-center"
|
||||||
{% if "ci-auto-update" in infos %}
|
{% if "ci-auto-update" in infos %}
|
||||||
<a href="{{ infos["ci-auto-update"]["url"] }}">
|
<a href="{{ infos["ci-auto-update"]["url"] }}">
|
||||||
<i class="fa fa-arrow-up"></i>
|
<i class="fa fa-arrow-up"></i>
|
||||||
|
@ -175,7 +177,7 @@
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-sm">
|
<td class="px-3 truncate text-sm max-w-16 sm:max-w-full">
|
||||||
{% if this_app_stars > 0 %}
|
{% if this_app_stars > 0 %}
|
||||||
<span class="text-xs border-purple-400 text-purple-600 px-1 py-0 border rounded">{{ this_app_stars }}
|
<span class="text-xs border-purple-400 text-purple-600 px-1 py-0 border rounded">{{ this_app_stars }}
|
||||||
<i class="fa {% if not user_starred_this_app %}fa-star-o{% else %}fa-star{% endif %}" aria-hidden="true" title="{{ _("Popularity stars") }}"></i>
|
<i class="fa {% if not user_starred_this_app %}fa-star-o{% else %}fa-star{% endif %}" aria-hidden="true" title="{{ _("Popularity stars") }}"></i>
|
||||||
|
@ -202,6 +204,7 @@
|
||||||
|
|
||||||
<div id="nbEntriesFound" class="text-center text-gray-600 text-sm py-3"></div>
|
<div id="nbEntriesFound" class="text-center text-gray-600 text-sm py-3"></div>
|
||||||
|
|
||||||
|
<div class="text-center text-gray-600 text-sm py-3">{{ _("Last data update %(time)s ago", time=last_data_update|hours_ago) }}</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
@ -276,7 +279,7 @@
|
||||||
}
|
}
|
||||||
else if (filterName == "testings")
|
else if (filterName == "testings")
|
||||||
{
|
{
|
||||||
if (entries[i].dataset.lastUpdateTestingDaysago)
|
if (parseInt(entries[i].dataset.lastUpdateTesting) > -1)
|
||||||
{
|
{
|
||||||
entries[i].classList.remove("hidden");
|
entries[i].classList.remove("hidden");
|
||||||
nb_found++;
|
nb_found++;
|
||||||
|
@ -288,7 +291,7 @@
|
||||||
}
|
}
|
||||||
else if (filterName == "autoupdate")
|
else if (filterName == "autoupdate")
|
||||||
{
|
{
|
||||||
if (entries[i].dataset.lastUpdateAutoupdateDaysago)
|
if (parseInt(entries[i].dataset.lastUpdateAutoupdate) > -1)
|
||||||
{
|
{
|
||||||
entries[i].classList.remove("hidden");
|
entries[i].classList.remove("hidden");
|
||||||
nb_found++;
|
nb_found++;
|
||||||
|
@ -337,12 +340,12 @@
|
||||||
}
|
}
|
||||||
else if (sortBy === "main_branch_update") {
|
else if (sortBy === "main_branch_update") {
|
||||||
toSort.sort(function(a, b) {
|
toSort.sort(function(a, b) {
|
||||||
return parseInt(a.dataset.lastUpdateMasterDaysago) < parseInt(b.dataset.lastUpdateMasterDaysago) ? 1 : -1;
|
return parseInt(a.dataset.lastUpdateMaster) < parseInt(b.dataset.lastUpdateMaster) ? 1 : -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (sortBy === "testing_branch_update") {
|
else if (sortBy === "testing_branch_update") {
|
||||||
toSort.sort(function(a, b) {
|
toSort.sort(function(a, b) {
|
||||||
return parseInt(a.dataset.lastUpdateTestingDaysago) < parseInt(b.dataset.lastUpdateTestingDaysago) ? 1 : -1;
|
return parseInt(a.dataset.lastUpdateTesting) < parseInt(b.dataset.lastUpdateTesting) ? 1 : -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (sortBy === "alpha") {
|
else if (sortBy === "alpha") {
|
||||||
|
@ -367,7 +370,7 @@
|
||||||
if ('URLSearchParams' in window) {
|
if ('URLSearchParams' in window) {
|
||||||
var queryArgs = new URLSearchParams(window.location.search)
|
var queryArgs = new URLSearchParams(window.location.search)
|
||||||
if (filterName != "none") { queryArgs.set("filter", filterName) } else { queryArgs.delete("filter"); };
|
if (filterName != "none") { queryArgs.set("filter", filterName) } else { queryArgs.delete("filter"); };
|
||||||
if (sortBy != "alpha") { queryArgs.set("sort", sortBy) } else { queryArgs.delete("sort"); };
|
if (sortBy != "stars") { queryArgs.set("sort", sortBy) } else { queryArgs.delete("sort"); };
|
||||||
if (starsOnly) { queryArgs.set("starsonly", true) } else { queryArgs.delete("starsonly"); };
|
if (starsOnly) { queryArgs.set("starsonly", true) } else { queryArgs.delete("starsonly"); };
|
||||||
|
|
||||||
let newUrl;
|
let newUrl;
|
||||||
|
|
Loading…
Add table
Reference in a new issue