Improve /integrations page load time.

Prior to this commit, 7 megabytes of images (through 253 individual requests)
were heavily slowing down the initial load. With this commit, we load only the
logos (60 or so images).

Documentation and images for the individual integration sub-pages is requested
separately using the /integrations/doc/ endpoint, which returns HTML.
This commit is contained in:
Jack Zhang 2017-07-11 17:50:27 -07:00 committed by Tim Abbott
parent 9ddef6a4da
commit 6e2f90c8c9
6 changed files with 37 additions and 8 deletions

View File

@ -1,4 +1,5 @@
import fuzzysearch from 'fuzzysearch'; import fuzzysearch from 'fuzzysearch';
import blueslip from './../blueslip';
// this will either smooth scroll to an anchor where the `name` // this will either smooth scroll to an anchor where the `name`
// is the same as the `scroll-to` reference, or to a px height // is the same as the `scroll-to` reference, or to a px height
@ -56,6 +57,18 @@ var integration_events = function () {
var show_integration = function (hash) { var show_integration = function (hash) {
// the version of the hash without the leading "#". // the version of the hash without the leading "#".
var _hash = hash.replace(/^#/, ""); var _hash = hash.replace(/^#/, "");
var integration_name = _hash;
$.get({
url: '/integrations/doc/' + integration_name,
dataType: 'html',
success: function (doc) {
$('#' + integration_name + '.integration-instructions .help-content').html(doc);
},
error: function (err) {
blueslip.error("Integration documentation for '" + integration_name + "' not found.", err);
},
});
// clear out the integrations instructions that may exist in the instruction // clear out the integrations instructions that may exist in the instruction
// block from a previous hash. // block from a previous hash.

View File

@ -111,7 +111,7 @@
{% for integration in integrations_dict.values() %} {% for integration in integrations_dict.values() %}
{% if integration.is_enabled() %} {% if integration.is_enabled() %}
<div id={{ integration.name }} class="integration-instructions"> <div id={{ integration.name }} class="integration-instructions">
{{ integration.help_content }} <div class="help-content"></div>
<p style="font-size:11px; font-style:italic;"> <p style="font-size:11px; font-style:italic;">
Logos are trademarks of their respective owners. Logos are trademarks of their respective owners.
None of the integrations on this page are created by, None of the integrations on this page are created by,

View File

@ -93,12 +93,6 @@ class Integration(object):
# type: (Dict[Any, Any]) -> None # type: (Dict[Any, Any]) -> None
self.doc_context = context self.doc_context = context
@property
def help_content(self):
# type: () -> Text
doc_context = self.doc_context or {}
return render_markdown_path(self.doc, doc_context)
class EmailIntegration(Integration): class EmailIntegration(Integration):
def is_enabled(self): def is_enabled(self):
# type: () -> bool # type: () -> bool

View File

@ -46,6 +46,7 @@ class DocPageTest(ZulipTestCase):
'Zapier', 'Zapier',
'IFTTT' 'IFTTT'
]) ])
self._test('/integrations/doc/travis', 'Your Travis CI notifications may look like:')
self._test('/devlogin/', 'Normal users') self._test('/devlogin/', 'Normal users')
self._test('/devtools/', 'Useful development URLs') self._test('/devtools/', 'Useful development URLs')
self._test('/errors/404/', 'Page not found') self._test('/errors/404/', 'Page not found')
@ -53,6 +54,9 @@ class DocPageTest(ZulipTestCase):
self._test('/emails/', 'Road Runner invited you to join Acme Corporation') self._test('/emails/', 'Road Runner invited you to join Acme Corporation')
self._test('/register/', 'Sign up for Zulip') self._test('/register/', 'Sign up for Zulip')
result = self.client_get('/integrations/doc/nonexistent_integration', follow=True)
self.assertEqual(result.status_code, 404)
result = self.client_get('/new-user/') result = self.client_get('/new-user/')
self.assertEqual(result.status_code, 301) self.assertEqual(result.status_code, 301)
self.assertIn('hello', result['Location']) self.assertIn('hello', result['Location'])

View File

@ -10,9 +10,11 @@ from django.shortcuts import render
import os import os
import ujson import ujson
from zerver.decorator import has_request_variables, REQ
from zerver.lib import bugdown from zerver.lib import bugdown
from zerver.lib.integrations import CATEGORIES, INTEGRATIONS, HUBOT_LOZENGES from zerver.lib.integrations import CATEGORIES, INTEGRATIONS, HUBOT_LOZENGES
from zerver.lib.utils import get_subdomain from zerver.lib.utils import get_subdomain
from zerver.templatetags.app_filters import render_markdown_path
def add_api_uri_context(context, request): def add_api_uri_context(context, request):
# type: (Dict[str, Any], HttpRequest) -> None # type: (Dict[str, Any], HttpRequest) -> None
@ -94,7 +96,7 @@ def add_integrations_context(context):
context['integrations_dict'] = alphabetical_sorted_integration context['integrations_dict'] = alphabetical_sorted_integration
context['hubot_lozenges_dict'] = alphabetical_sorted_hubot_lozenges context['hubot_lozenges_dict'] = alphabetical_sorted_hubot_lozenges
if context["html_settings_links"]: if "html_settings_links" in context and context["html_settings_links"]:
settings_html = '<a href="../#settings">Zulip settings page</a>' settings_html = '<a href="../#settings">Zulip settings page</a>'
subscriptions_html = '<a target="_blank" href="../#streams">streams page</a>' subscriptions_html = '<a target="_blank" href="../#streams">streams page</a>'
else: else:
@ -121,6 +123,20 @@ class IntegrationView(ApiURLView):
return context return context
@has_request_variables
def integration_doc(request, integration_name=REQ(default=None)):
# type: (HttpRequest, str) -> HttpResponse
try:
integration = INTEGRATIONS[integration_name]
except KeyError:
return HttpResponseNotFound()
context = integration.doc_context or {}
add_integrations_context(context)
doc_html_str = render_markdown_path(integration.doc, context)
return HttpResponse(doc_html_str)
def api_endpoint_docs(request): def api_endpoint_docs(request):
# type: (HttpRequest) -> HttpResponse # type: (HttpRequest) -> HttpResponse
context = {} # type: Dict[str, Any] context = {} # type: Dict[str, Any]

View File

@ -140,6 +140,8 @@ i18n_urls = [
url(r'^api/$', APIView.as_view(template_name='zerver/api.html')), url(r'^api/$', APIView.as_view(template_name='zerver/api.html')),
url(r'^api/endpoints/$', zerver.views.integrations.api_endpoint_docs, name='zerver.views.integrations.api_endpoint_docs'), url(r'^api/endpoints/$', zerver.views.integrations.api_endpoint_docs, name='zerver.views.integrations.api_endpoint_docs'),
url(r'^integrations/$', IntegrationView.as_view()), url(r'^integrations/$', IntegrationView.as_view()),
url(r'^integrations/doc/(?P<integration_name>[^/]*)$', zerver.views.integrations.integration_doc,
name="zerver.views.integrations.integration_doc"),
url(r'^about/$', TemplateView.as_view(template_name='zerver/about.html')), url(r'^about/$', TemplateView.as_view(template_name='zerver/about.html')),
url(r'^apps/$', zerver.views.home.apps_view, name='zerver.views.home.apps_view'), url(r'^apps/$', zerver.views.home.apps_view, name='zerver.views.home.apps_view'),