Skip to content

Commit a36a1dc

Browse files
committed
Clean up analytics and embed pages.
Add dynamic help
1 parent c3963ea commit a36a1dc

File tree

10 files changed

+274
-33
lines changed

10 files changed

+274
-33
lines changed

media/css/core.css

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,54 @@ select.dropdown { display: none; }
632632
.badge > ul { margin-top: 3px; position:absolute; top:100%; background:#465158; padding:4px; border-radius:4px; z-index:1005; min-width:500; box-shadow: 0px 0px 8px 2px rgba(0,0,0,0.2); }
633633
.badge > ul > li { background: white; padding:8px 10px; border-bottom:1px solid #EEE; }
634634
.badge pre { font-size: 12px; }
635+
636+
#help_container > a { float:right; }
637+
638+
639+
640+
/* CHART LISTS */
641+
.chartlist {
642+
float: left;
643+
border-top: 1px solid #EEE;
644+
width: 15em;
645+
}
646+
.chartlist li {
647+
position: relative;
648+
display: block;
649+
border-bottom: 1px solid #EEE;
650+
_zoom: 1;
651+
}
652+
.chartlist li a {
653+
display: block;
654+
padding: 0.4em 4.5em 0.4em 0.5em;
655+
position: relative;
656+
z-index: 2;
657+
}
658+
.chartlist .count {
659+
display: block;
660+
position: absolute;
661+
top: 0;
662+
right: 0;
663+
margin: 0 0.3em;
664+
text-align: right;
665+
color: #999;
666+
font-weight: bold;
667+
font-size: 0.875em;
668+
line-height: 2em;
669+
z-index: 5;
670+
}
671+
.chartlist .index {
672+
display: block;
673+
position: absolute;
674+
top: 0;
675+
left: 0;
676+
height: 100%;
677+
background: #B8E4F5;
678+
text-indent: -9999px;
679+
overflow: hidden;
680+
line-height: 2em;
681+
z-index: 1;
682+
}
683+
.chartlist li:hover {
684+
background: #EFEFEF;
685+
}

readthedocs/core/templatetags/core_tags.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,7 @@ def url_replace(request, field, value):
9595
dict_[field] = value
9696
return dict_.urlencode()
9797

98+
99+
@register.filter
100+
def key(d, key_name):
101+
return d[key_name]

readthedocs/projects/urls/public.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,13 @@
4646
'projects.views.public.project_versions',
4747
name='project_version_list'),
4848

49-
url(r'^(?P<project_slug>[-\w]+)/tools/$',
50-
'projects.views.public.project_tools',
51-
name='project_tools'),
49+
url(r'^(?P<project_slug>[-\w]+)/tools/embed/$',
50+
'projects.views.public.project_embed',
51+
name='project_embed'),
52+
53+
url(r'^(?P<project_slug>[-\w]+)/tools/analytics/$',
54+
'projects.views.public.project_analytics',
55+
name='project_analytics'),
5256

5357
url(r'^(?P<project_slug>[-\w]+)/search/$',
5458
'projects.views.public.elastic_project_search',

readthedocs/projects/views/public.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import collections
2+
import operator
13
import os
24
import json
35
import logging
46
import mimetypes
57
import md5
68

79
from django.core.urlresolvers import reverse
10+
from django.core.cache import cache
811
from django.conf import settings
912
from django.contrib.auth.models import User
1013
from django.http import HttpResponse, HttpResponseRedirect, Http404
@@ -93,7 +96,6 @@ def get_context_data(self, **kwargs):
9396
project.get_default_version(),
9497
)
9598

96-
9799
return context
98100

99101

@@ -385,7 +387,42 @@ def project_versions(request, project_slug):
385387
)
386388

387389

388-
def project_tools(request, project_slug):
390+
def project_analytics(request, project_slug):
391+
"""
392+
Have a analytics API placeholder
393+
"""
394+
project = get_object_or_404(Project.objects.protected(request.user),
395+
slug=project_slug)
396+
analytics_cache = cache.get('analytics:%s' % project_slug)
397+
if analytics_cache:
398+
analytics = json.loads(analytics_cache)
399+
else:
400+
try:
401+
resp = requests.get('https://api.grokthedocs.com/api/v1/index/1/heatmap/', params={'project': project.slug, 'days': 7, 'compare': True})
402+
analytics = resp.json()
403+
except:
404+
analytics = None
405+
406+
if analytics:
407+
page_list = reversed(sorted(analytics['page'].items(), key=operator.itemgetter(1)))
408+
version_list = reversed(sorted(analytics['version'].items(), key=operator.itemgetter(1)))
409+
else:
410+
page_list = []
411+
version_list = []
412+
413+
return render_to_response(
414+
'projects/project_analytics.html',
415+
{
416+
'project': project,
417+
'analytics': analytics,
418+
'page_list': page_list,
419+
'version_list': version_list,
420+
},
421+
context_instance=RequestContext(request)
422+
)
423+
424+
425+
def project_embed(request, project_slug):
389426
"""
390427
Have a content API placeholder
391428
"""
@@ -394,18 +431,11 @@ def project_tools(request, project_slug):
394431
version = project.versions.get(slug='latest')
395432
files = version.imported_files.order_by('path')
396433

397-
try:
398-
resp = requests.get('https://api.grokthedocs.com/api/v1/index/1/heatmap/', params={'project': project.slug, 'compare': True})
399-
analytics = resp.json()
400-
except:
401-
analytics = None
402-
403434
return render_to_response(
404-
'projects/project_tools.html',
435+
'projects/project_embed.html',
405436
{
406437
'project': project,
407438
'files': files,
408-
'analytics': analytics,
409439
},
410440
context_instance=RequestContext(request)
411441
)

readthedocs/restapi/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
urlpatterns = patterns(
1414
'',
1515
url(r'^', include(router.urls)),
16+
url(r'docurl/', 'restapi.views.core_views.docurl', name='docurl'),
1617
url(r'cname/', 'restapi.views.core_views.cname', name='cname'),
1718
url(r'footer_html/', 'restapi.views.footer_views.footer_html', name='footer_html'),
1819
url(r'quick_search/', 'restapi.views.search_views.quick_search', name='quick_search'),

readthedocs/restapi/views/core_views.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
from rest_framework.renderers import JSONPRenderer, JSONRenderer, BrowsableAPIRenderer
33
from rest_framework.response import Response
44

5+
from django.shortcuts import get_object_or_404
6+
57
from core.utils import clean_url, cname_to_slug
8+
from builds.models import Version
69
from projects.models import Project
10+
from core.templatetags.core_tags import make_document_url
11+
712

813
@decorators.api_view(['GET'])
914
@decorators.permission_classes((permissions.AllowAny,))
@@ -26,8 +31,31 @@ def cname(request):
2631
host = clean_url(host)
2732
slug = cname_to_slug(host)
2833
return Response({
29-
'host': host,
30-
'slug': slug,
34+
'host': host,
35+
'slug': slug,
36+
})
37+
38+
39+
@decorators.api_view(['GET'])
40+
@decorators.permission_classes((permissions.AllowAny,))
41+
@decorators.renderer_classes((JSONRenderer, JSONPRenderer, BrowsableAPIRenderer))
42+
def docurl(request):
43+
"""
44+
Get the url that a slug resolves to.
45+
46+
Example::
47+
48+
GET https://readthedocs.org/api/v2/docurl/?project=requests&version=latest&doc=index
49+
50+
"""
51+
project = request.GET.get('project')
52+
version = request.GET.get('version', 'latest')
53+
doc = request.GET.get('doc', 'index')
54+
55+
project = get_object_or_404(Project, slug=project)
56+
version = get_object_or_404(Version.objects.public(request.user, project=project, only_active=False), slug=version)
57+
return Response({
58+
'url': make_document_url(project=project, version=version.slug, page=doc)
3159
})
3260

3361

readthedocs/templates/core/project_bar_base.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ <h1>
4545

4646
<li class="{{ versions_active }}"><a href="{% url "project_version_list" project.slug %}">{% trans "Versions" %}</a></li>
4747

48-
<li class="{{ tools_active }}"><a href="{% url "project_tools" project.slug %}">{% trans "Tools" %}</a></li>
48+
<li class="{{ tools_active }}"><a href="{% url 'project_embed' project.slug %}">{% trans "Tools" %}</a></li>
4949

5050
{% if request.user|is_admin:project %}
5151
<li class="{{ edit_active }} project-admin"><a href="{% url "projects_edit" project.slug %}"><i class="gear"></i>{% trans "Admin" %}</a></li>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{% extends "projects/base_project.html" %}
2+
{% load i18n %}
3+
{% load privacy_tags %}
4+
{% load core_tags highlight %}
5+
6+
{% block title %}
7+
Tools
8+
{% endblock title %}
9+
10+
{% block project_editing %}
11+
{% with tools_active="active" %}
12+
{% include "core/project_bar.html" %}
13+
{% endwith %}
14+
{% endblock %}
15+
16+
{% block extra_scripts %}
17+
<link rel="stylesheet" href="http://localhost:5555/static/css/public.css">
18+
<script type="text/javascript">
19+
var READTHEDOCS_EMBED = {
20+
'project': 'docs',
21+
'version': 'latest',
22+
'doc': 'business/analytics',
23+
'section': 'viewing'
24+
}
25+
</script>
26+
<script type="text/javascript" src="http://localhost:5555/static/javascript/bundle-public.js"></script>
27+
{% endblock %}
28+
29+
{% block content %}
30+
31+
<div class="navigable">
32+
33+
<ul>
34+
<li class="active">
35+
<a href="{% url 'project_analytics' project.slug %}">Analytics</a>
36+
</li>
37+
<li>
38+
<a href="{% url 'project_embed' project.slug %}">Embed</a>
39+
</li>
40+
</ul>
41+
42+
43+
<div>
44+
<div id="help_container">
45+
<a href="#" class="quiet readthedocs-help-embed">(Help)</a>
46+
</div>
47+
48+
<h1> {% trans "Analytics" %} </h1>
49+
50+
51+
<p class="help_text">
52+
{% trans "This shows the last 7 days of data from your project." %}
53+
</p>
54+
55+
<h3> {% trans "Pages" %} </h3>
56+
<ul class="chartlist">
57+
{% for page, count in page_list %}
58+
<li>
59+
<a href="{% doc_url project project.default_version page %}">{{ page }}</a>
60+
<span class="count">{{ count }}</span>
61+
<span class="index" style="width: {{ analytics.scaled_page|key:page }}%">({{ analytics.scaled_page|key:page }}%)</span>
62+
</li>
63+
{% endfor %}
64+
</ul>
65+
</div>
66+
67+
68+
<div style="float: right;">
69+
<h3> {% trans "Versions" %} </h3>
70+
<ul class="chartlist">
71+
{% for version, count in version_list %}
72+
<li>
73+
<a href="{% doc_url project version %}">{{ version }}</a>
74+
<span class="count">{{ count }}</span>
75+
<span class="index" style="width: {{ analytics.scaled_version|key:version }}%">({{ analytics.scaled_version|key:version }}%)</span>
76+
</li>
77+
{% endfor %}
78+
</ul>
79+
80+
</div>
81+
82+
</div>
83+
84+
{% endblock %}

0 commit comments

Comments
 (0)