Skip to content

Commit 3585df0

Browse files
authored
Improve page load performance on listing views (#404)
* Use API permissions check instead of is_admin filter on project listing * Linting fixes
1 parent ff74196 commit 3585df0

File tree

3 files changed

+73
-68
lines changed

3 files changed

+73
-68
lines changed

readthedocsext/theme/static/readthedocsext/theme/js/site.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{% extends "includes/crud/table_list.html" %}
22

3-
{% load i18n %}
4-
{% load humanize %}
5-
6-
{% load privacy_tags %}
7-
{% load projects_tags %}
3+
{% load blocktrans trans from i18n %}
4+
{% load naturaltime from humanize %}
85

96
{% block top_left_menu_items %}
10-
<div data-bind="using: FilterView()">{% include "includes/filters/form.html" with fields=filter.form %}</div>
7+
<div data-bind="using: FilterView()">
8+
{% include "includes/filters/form.html" with fields=filter.form %}
9+
</div>
1110
{% endblock top_left_menu_items %}
1211

1312
{% block create_button %}
@@ -31,72 +30,71 @@
3130
{% endblock list_placeholder_text_empty %}
3231

3332
{% block list_item_start %}
34-
<tr data-bind="using: ProjectListItemView({id: {{ object.id }}, url: '{% url "project-detail" object.pk %}'})">
35-
{% endblock list_item_start %}
36-
37-
{% block list_item_right_menu %}
38-
<div class="ui small icon buttons">
39-
{% blocktrans trimmed with project=object.name asvar label_link %}
40-
View documentation for project {{ project }}
41-
{% endblocktrans %}
42-
<a class="ui {% if not object.has_good_build %}disabled{% endif %} button"
43-
data-content="{{ label_link }}"
44-
aria-label="{{ label_link }}"
45-
data-bind="event: {mouseover: fetch, focusin: fetch}, attr: {href: url_docs}"
46-
target="_blank"
47-
tabindex="{% if object.has_good_build %}0{% else %}-1{% endif %}">
48-
<i class="fa-duotone fa-book icon"></i>
49-
</a>
50-
51-
{% if request.user|is_admin:object %}
52-
<button class="ui dropdown button">
53-
<i class="fa-solid fa-ellipsis icon"></i>
54-
<div class="menu">
55-
<div class="header">{% trans "Admin" %}</div>
56-
<a class="item" href="{% url "projects_edit" object.slug %}">
57-
<i class="fa-duotone fa-wrench icon"></i>
58-
{% trans "Configure project" %}
59-
</a>
60-
</div>
61-
</button>
62-
{% else %}
63-
<button class="ui disabled dropdown button">
64-
<i class="fa-solid fa-ellipsis icon"></i>
65-
</button>
66-
{% endif %}
33+
{# djlint:off #}
34+
<tr data-bind="using: ProjectListItemView({id: {{ object.id }}, url: '{% url "projects-detail" object.slug %}'})">
35+
{# djlint:on #}
36+
{% endblock list_item_start %}
6737

68-
</div>
69-
{% endblock list_item_right_menu %}
38+
{% block list_item_right_menu %}
39+
<div class="ui small icon buttons"
40+
data-bind="event: {mouseover: fetch, focusin: fetch}">
41+
{% blocktrans trimmed with project=object.name asvar label_link %}
42+
View documentation for project {{ project }}
43+
{% endblocktrans %}
44+
<a class="ui {% if not object.has_good_build %}disabled{% endif %} button"
45+
data-content="{{ label_link }}"
46+
aria-label="{{ label_link }}"
47+
data-bind="attr: {href: url_docs}"
48+
target="_blank"
49+
tabindex="{% if object.has_good_build %}0{% else %}-1{% endif %}">
50+
<i class="fa-duotone fa-book icon"></i>
51+
</a>
7052

71-
{% block list_item_image %}
72-
{% include "projects/includes/project_image.html" with project=object %}
73-
{% endblock list_item_image %}
53+
<button class="ui dropdown button">
54+
<i class="fa-solid fa-ellipsis icon"></i>
55+
<div class="menu">
56+
<div class="header">{% trans "Admin" %}</div>
57+
<a class="disabled item"
58+
href="{% url "projects_edit" object.slug %}"
59+
data-bind="css: { disabled: !is_admin() }">
60+
<i class="fa-duotone fa-wrench icon"></i>
61+
{% trans "Configure project" %}
62+
</a>
63+
</div>
64+
</button>
7465

75-
{% block list_item_header %}
76-
<a href="{% url "projects_detail" object.slug %}">{{ object.name }}</a>
77-
<div class="sub header">
78-
{% if object.has_good_build %}
79-
{% with build=object.get_latest_build %}
80-
<time data-content="{{ build.date }}">
81-
{# Translators: this will read like "Last built 1 year, 5 months ago" #}
82-
{% blocktrans with time_since=build.date|naturaltime trimmed %}
83-
Last built {{ time_since }}
84-
{% endblocktrans %}
85-
</time>
86-
{% endwith %}
87-
{% else %}
88-
{% trans "Not built yet" %}
89-
{% endif %}
90-
</div>
91-
{% endblock list_item_header %}
66+
</div>
67+
{% endblock list_item_right_menu %}
9268

93-
{% block list_item_meta %}
94-
{% endblock list_item_meta %}
69+
{% block list_item_image %}
70+
{% include "projects/includes/project_image.html" with project=object %}
71+
{% endblock list_item_image %}
9572

96-
{% block list_item_extra_items %}
73+
{% block list_item_header %}
74+
<a href="{% url "projects_detail" object.slug %}">{{ object.name }}</a>
75+
<div class="sub header">
9776
{% if object.has_good_build %}
9877
{% with build=object.get_latest_build %}
99-
{% include "includes/elements/chips/build.html" with build=build %}
78+
<time data-content="{{ build.date }}">
79+
{# Translators: this will read like "Last built 1 year, 5 months ago" #}
80+
{% blocktrans with time_since=build.date|naturaltime trimmed %}
81+
Last built {{ time_since }}
82+
{% endblocktrans %}
83+
</time>
10084
{% endwith %}
85+
{% else %}
86+
{% trans "Not built yet" %}
10187
{% endif %}
102-
{% endblock list_item_extra_items %}
88+
</div>
89+
{% endblock list_item_header %}
90+
91+
{% block list_item_meta %}
92+
{% endblock list_item_meta %}
93+
94+
{% block list_item_extra_items %}
95+
{% if object.has_good_build %}
96+
{% with build=object.get_latest_build %}
97+
{% include "includes/elements/chips/build.html" with build=build %}
98+
{% endwith %}
99+
{% endif %}
100+
{% endblock list_item_extra_items %}

src/js/project/index.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,21 @@ export class ProjectListItemView extends APIListItemView {
2626
constructor(project) {
2727
super(project);
2828

29+
// Add expansion to API URL
30+
this.url = this.url + "?expand=permissions";
31+
2932
/** Asynchronously load documentation URL as rendering this URL for each
3033
* project slows the dashboard down considerably. Instead, this is only
3134
* fetched when it is needed.
3235
* @observable {string} Documentation URL for the project */
3336
this.url_docs = ko.observable();
37+
/* @observable {Boolean} Does the user have admin permissions on this? */
38+
this.is_admin = ko.observable(false);
39+
3440
// Subscribe to the data loaded via :class:`APIListItemView`
3541
this.data.subscribe((data) => {
36-
this.url_docs(data.canonical_url);
42+
this.url_docs(data.urls.documentation);
43+
this.is_admin(data.permissions.admin);
3744
});
3845
}
3946
}

0 commit comments

Comments
 (0)