removing inline JS, adding more local caching
This commit is contained in:
Родитель
3d1655e50e
Коммит
cd9eb2faee
|
@ -1,49 +1,33 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block stats %}
|
||||
{% block chart_config %}
|
||||
data-series="applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6.3,applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6"
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6.3"
|
||||
data-format="number">
|
||||
{{_('Firefox 3.6.3')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6"
|
||||
data-format="number">
|
||||
{{_('Firefox 3.6')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.seriesList = {
|
||||
metric: "apps",
|
||||
fields: [
|
||||
"applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6.3",
|
||||
"applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6",
|
||||
]
|
||||
};
|
||||
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Firefox 3.6.3",
|
||||
field: 'applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6.3',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Firefox 3.6",
|
||||
field: 'applications|{ec8030f7-c20a-464f-9b0e-13a3a9e97384}|3.6',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,29 +1,36 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block chart_config %}
|
||||
data-series="count"
|
||||
{% endblock %}
|
||||
|
||||
{% block stats %}
|
||||
<div class="featured">
|
||||
<div class="featured-inner">
|
||||
<div class="featured-body tabular">
|
||||
<table class="stats-aggregate"><thead>
|
||||
<tr><th>{{_('Category')}}</th><th>Last 7 Days</th><th>7-14 Days Ago</th><th>{{_('All Time')}}</th></tr>
|
||||
<table class="stats-aggregate" data-field="count"><thead>
|
||||
<tr><th>{{_('Category')}}</th><th class="range"></th><th class="prev_range"></th><th>{{_('All Time')}}</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="label">{{_('Total Downloads')}}</td>
|
||||
<td class="value"><span class="value aggregate" id="sum_range"></span><span class="change" id="sum_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="sum_prev_range"></span><span class="change" id="sum_prev_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="sum_all_time"></span><span class="change"> </span></td>
|
||||
<td class="value"><span class="value aggregate" id="sum_all_time">{{ addon.total_downloads|numberfmt }}</span><span class="change"> </span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">{{_('Average Downloads/Day')}}</td>
|
||||
<td class="value"><span class="value aggregate" id="mean_range"></span><span class="change" id="mean_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="mean_prev_range"></span><span class="change" id="mean_prev_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="mean_all_time"></span><span class="change"> </span></td>
|
||||
<td class="value"><span class="value aggregate" id="mean_all_time">{{ addon.average_daily_downloads|numberfmt }}</span><span class="change"> </span></td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
<h3>{{_('Downloads by Date')}}</h3>
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
|
@ -43,6 +50,7 @@
|
|||
{{_('Count')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,57 +1,39 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block stats %}
|
||||
{% block chart_config %}
|
||||
data-series="locales|en-US,locales|es-ES,locales|de"
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="locales|en-US"
|
||||
data-format="number">
|
||||
{{_('English (US)')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="locales|es-ES"
|
||||
data-format="number">
|
||||
{{_('Spanish')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="locales|de"
|
||||
data-format="number">
|
||||
{{_('German')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.seriesList = {
|
||||
metric: "locales",
|
||||
fields: [
|
||||
"locales|en-US",
|
||||
"locales|es-ES",
|
||||
"locales|de"
|
||||
]
|
||||
};
|
||||
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('English (US)')}}",
|
||||
field: 'locales|en-US',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Spanish')}}",
|
||||
field: 'locales|es-ES',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('German')}}",
|
||||
field: 'locales|de',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -1,57 +1,38 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block stats %}
|
||||
{% block chart_config %}
|
||||
data-series="oses|WINNT,oses|Darwin,oses|Linux"
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="oses|WINNT"
|
||||
data-format="number">
|
||||
{{_('Windows')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="oses|Darwin"
|
||||
data-format="number">
|
||||
{{_('Mac')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="oses|Linux"
|
||||
data-format="number">
|
||||
{{_('Linux')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.seriesList = {
|
||||
metric: "os",
|
||||
fields: [
|
||||
"oses|WINNT",
|
||||
"oses|Darwin",
|
||||
"oses|Linux"
|
||||
]
|
||||
};
|
||||
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Windows')}}",
|
||||
field: 'oses|WINNT',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Mac')}}",
|
||||
field: 'oses|Darwin',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Linux')}}",
|
||||
field: 'oses|Linux',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,10 +1,33 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block chart_config %}
|
||||
data-series="count"
|
||||
{% endblock %}
|
||||
|
||||
{% block chart_menu %}
|
||||
<ul id='series-select'>
|
||||
<li class="selected">
|
||||
<a href="#"
|
||||
data-report='downloads'
|
||||
data-series='count'>
|
||||
{{_('Downloads')}}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"
|
||||
data-report='usage'
|
||||
data-series='count'>
|
||||
{{_('Daily Users')}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block stats %}
|
||||
<div class="featured">
|
||||
<div class="featured-inner three-up">
|
||||
<div><a href="#">850,749 Downloads</a><br/><small>16,534 in last 30 days</small></div>
|
||||
<div><a href="#">672,501 Daily Users</a><br/><small>634,475 in last 30 days</small></div>
|
||||
<div><a href="#">{{ addon.total_downloads|numberfmt }} Downloads</a><br/><small>16,534 in last 30 days</small></div>
|
||||
<div><a href="#">{{ addon.average_daily_users|numberfmt }} Daily Users</a><br/><small>634,475 in last 30 days</small></div>
|
||||
<div><a href="#">$956.00 Contributed</a><br/><small>$83.00 in last 30 days</small></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,57 +1,38 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block stats %}
|
||||
{% block chart_config %}
|
||||
data-series="sources|api,sources|search,sources|collection"
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="sources|api"
|
||||
data-format="number">
|
||||
{{_('API')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="sources|search"
|
||||
data-format="number">
|
||||
{{_('Search')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="sources|collection"
|
||||
data-format="number">
|
||||
{{_('Collections')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.seriesList = {
|
||||
metric: "sources",
|
||||
fields: [
|
||||
"sources|api",
|
||||
"sources|search",
|
||||
"sources|collection"
|
||||
]
|
||||
};
|
||||
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('API')}}",
|
||||
field: 'sources|api',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Search')}}",
|
||||
field: 'sources|search',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Collection')}}",
|
||||
field: 'sources|collection',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -48,6 +48,7 @@
|
|||
<div class="primary statistics"
|
||||
data-report="{{ report }}"
|
||||
data-addon_id="{{ addon.id }}"
|
||||
data-base_url="{{ stats_base_url }}"
|
||||
>
|
||||
{% if true %}
|
||||
<div class="custom criteria hidden">
|
||||
|
@ -64,31 +65,32 @@
|
|||
</select>
|
||||
<button id="date-range-submit" type="submit">Update</button>
|
||||
</form>
|
||||
<!-- <ul><li>From</li><li class="selected"><a>Control 1</a></li></ul> -->
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="featured">
|
||||
<div class="featured-inner chart">
|
||||
<div class="listing-header"><ul><li class="selected"> </li></ul></div>
|
||||
<div class="featured-body" id="head-chart" style="background:#fff;height:256px"></div>
|
||||
<div class="listing-header">
|
||||
{% block chart_menu %}
|
||||
<ul><li class="selected"> </li></ul>
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="featured-body" id="head-chart" style="background:#fff;height:256px"
|
||||
{% block chart_config %}
|
||||
data-series="{{ series_fields }}"
|
||||
{% endblock %}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block stats %}
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
(function () {
|
||||
var stats_base_url = '{{ stats_base_url }}/';
|
||||
AMO.getStatsBaseURL = function () { return stats_base_url };
|
||||
})();
|
||||
</script>
|
||||
{% block chartconfig %}
|
||||
{% endblock %}
|
||||
<script src="{{ MEDIA_URL }}js/zamboni/jquery-datepicker.js"></script>
|
||||
<script src="{{ MEDIA_URL }}js/zamboni/highcharts.src.js"></script>
|
||||
<!--[if IE]>
|
||||
|
|
|
@ -1,66 +1,44 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block chart_config %}
|
||||
data-series="statuses|userEnabled,statuses|userDisabled"
|
||||
{% endblock %}
|
||||
|
||||
{% block stats %}
|
||||
<h3>{{_('Add-on Status by Date')}}</h3>
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="statuses|userEnabled"
|
||||
data-format="number">
|
||||
{{_('Enabled')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="statuses|userDisabled"
|
||||
data-format="number">
|
||||
{{_('Disabled')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="userEnabled,incompatible"
|
||||
data-format="number">
|
||||
{{_('Enabled (incompatible)')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="userDisabled,incompatible"
|
||||
data-format="number">
|
||||
{{_('Disabled (incompatible)')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.seriesList = {
|
||||
metric: "statuses",
|
||||
fields: [
|
||||
"statuses|userEnabled",
|
||||
"statuses|userDisabled",
|
||||
"statuses|userEnabled,incompatible"
|
||||
]
|
||||
};
|
||||
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Enabled')}}",
|
||||
field: 'statuses|userEnabled',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Disabled')}}",
|
||||
field: 'statuses|userDisabled',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Enabled (Incompatible)')}}",
|
||||
field: 'statuses|userEnabled,incompatible',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Disabled (Incompatible)')}}",
|
||||
field: 'statuses|userDisabled,incompatible',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,24 +1,28 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block chart_config %}
|
||||
data-series="count"
|
||||
{% endblock %}
|
||||
|
||||
{% block stats %}
|
||||
<div class="featured">
|
||||
<div class="featured-inner">
|
||||
<div class="featured-body tabular">
|
||||
<table class="stats-overview"><thead>
|
||||
<table class="stats-aggregate" data-field="count"><thead>
|
||||
<tr><th>{{_('Category')}}</th><th>Last 7 Days</th><th>7-14 Days Ago</th><th>{{_('All Time')}}</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="label">{{_('Average Daily Users')}}</td>
|
||||
<td class="value"><span class="value" id="sum_range"></span><span class="change" id="sum_diff"></span></td>
|
||||
<td class="value"><span class="value" id="sum_prev_range"></span><span class="change" id="sum_prev_diff"></span></td>
|
||||
<td class="value"><span class="value" id="sum_all_time"></span><span class="change"> </span></td>
|
||||
<td class="value"><span class="value aggregate" id="mean_range"></span><span class="change" id="mean_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="mean_prev_range"></span><span class="change" id="mean_prev_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="mean_all_time">{{ addon.average_daily_users|numberfmt }}</span><span class="change"> </span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">{{_('Max. Daily Users')}}</td>
|
||||
<td class="value"><span class="value" id="mean_range"></span><span class="change" id="mean_diff"></span></td>
|
||||
<td class="value"><span class="value" id="mean_prev_range"></span><span class="change" id="mean_prev_diff"></span></td>
|
||||
<td class="value"><span class="value" id="mean_all_time"></span><span class="change"> </span></td>
|
||||
<td class="value"><span class="value aggregate" id="max_range"></span><span class="change" id="max_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="max_prev_range"></span><span class="change" id="max_prev_diff"></span></td>
|
||||
<td class="value"><span class="value aggregate" id="max_all_time"></span><span class="change"> </span></td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
|
@ -30,41 +34,24 @@
|
|||
<h3>{{_('Daily Users by Date')}}</h3>
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="count"
|
||||
data-format="number"
|
||||
data-bar_column="true"
|
||||
data-bar_width="65%">
|
||||
{{_('Count')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "{{_('Count')}}",
|
||||
field: 'count',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}],
|
||||
barColumns: [{
|
||||
valueColumn: 2,
|
||||
barColor: '#26a2ce',
|
||||
className: 'bar',
|
||||
width: "65%"
|
||||
}]
|
||||
};
|
||||
AMO.aggregate_stats_field = {
|
||||
metric: "usage",
|
||||
name: "count"
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,57 +1,38 @@
|
|||
{% extends "stats/stats.html" %}
|
||||
|
||||
{% block stats %}
|
||||
{% block chart_config %}
|
||||
data-series="versions|1.2,versions|1.1,versions|1.0"
|
||||
{% endblock %}
|
||||
|
||||
{% block csvtable %}
|
||||
<div class="statbox">
|
||||
<div class="tabular">
|
||||
<table class="bar-table">
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
data-field="date"
|
||||
data-format="date">
|
||||
{{_('Date')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="versions|1.2"
|
||||
data-format="number">
|
||||
{{_('1.2')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="versions|1.1"
|
||||
data-format="number">
|
||||
{{_('1.1')}}
|
||||
</th>
|
||||
<th
|
||||
data-field="versions|1.0"
|
||||
data-format="number">
|
||||
{{_('1.0')}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chartconfig %}
|
||||
<script>
|
||||
AMO.seriesList = {
|
||||
metric: "versions",
|
||||
fields: [
|
||||
"versions|1.2",
|
||||
"versions|1.1",
|
||||
"versions|1.0"
|
||||
]
|
||||
};
|
||||
|
||||
AMO.csvTableConfig = {
|
||||
el: $("table.bar-table")[0],
|
||||
report: "{{ report }}",
|
||||
columns: [{
|
||||
label: "{{_('Date')}}",
|
||||
field: 'date',
|
||||
format: function (value) {
|
||||
return Highcharts.dateFormat('%a, %b %e, %Y', new Date(value));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "1.2",
|
||||
field: 'versions|1.2',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "1.1",
|
||||
field: 'versions|1.1',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "1.0",
|
||||
field: 'versions|1.0',
|
||||
format: function (value) {
|
||||
return Highcharts.numberFormat(value, 0);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}3
|
|
@ -32,8 +32,7 @@ urlpatterns = patterns('',
|
|||
url('^contributions/$', views.stats_report, name='stats.contributions',
|
||||
kwargs={'report': 'contributions'}),
|
||||
|
||||
# url('^downloads/sources/$', views.download, name='stats.download_sources'),
|
||||
# url('^usage/$', views.download, name='stats.usage'),
|
||||
|
||||
|
||||
# time series URLs following this pattern:
|
||||
# /addon/{addon_id}/statistics/{series}-{group}-{start}-{end}.{format}
|
||||
|
@ -56,7 +55,9 @@ urlpatterns = patterns('',
|
|||
url(series['apps'], views.usage_breakdown_series,
|
||||
name='stats.apps_series', kwargs={'field': 'applications'}),
|
||||
|
||||
|
||||
# special case time series
|
||||
url('^contributions-detail-%s\.%s$' % (range_re, format_re),
|
||||
views.contributions_detail, name='stats.contributions_detail'),
|
||||
|
||||
)
|
||||
|
|
|
@ -13,6 +13,7 @@ import jingo
|
|||
|
||||
from access import acl
|
||||
from addons.models import Addon
|
||||
from amo.urlresolvers import reverse
|
||||
from amo.helpers import locale_url
|
||||
|
||||
from .db import DayAvg, Avg
|
||||
|
@ -144,7 +145,7 @@ def usage_breakdown_series(request, addon_id, group,
|
|||
qs = UpdateCount.stats.filter(addon=addon_id,
|
||||
date__range=(start_date, end_date))
|
||||
gen = qs.period_summary(group, **dict(fields))
|
||||
|
||||
|
||||
if format == 'csv':
|
||||
gen, headings = csv_dynamic_prep(gen, qs, fields,
|
||||
'count', field)
|
||||
|
@ -181,7 +182,7 @@ def check_stats_permission(request, addon, for_contributions=False):
|
|||
|
||||
def stats_report(request, addon_id, report):
|
||||
addon = get_object_or_404(Addon.objects.valid(), id=addon_id)
|
||||
stats_base_url = locale_url('/addon/%d/statistics' % (addon.id))
|
||||
stats_base_url = reverse('stats.overview', args=[addon.id]);
|
||||
return jingo.render(request, 'stats/%s.html' % report,
|
||||
{'addon': addon,
|
||||
'report': report,
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
$(document).ready(function () {
|
||||
|
||||
var csvTable;
|
||||
|
||||
jQuery.fn.getData = function(name) {
|
||||
return this.attr("data-" + name);
|
||||
};
|
||||
|
||||
var addon_id = $(".primary").getData("addon_id");
|
||||
var reportName = $(".primary").getData("report");
|
||||
AMO.getAddonId = function () { return addon_id };
|
||||
AMO.getReportName = function () { return reportName };
|
||||
page_state.addon_id = $(".primary").getData("addon_id");
|
||||
page_state.report_name = $(".primary").getData("report");
|
||||
page_state.data_range = "30 days";
|
||||
page_state.chart_fields = $("#head-chart").getData("series").split(',') || ["count"];
|
||||
|
||||
|
||||
var stats_base_url = $(".primary").getData("base_url");
|
||||
AMO.aggregate_stats_field = $(".stats-aggregate").getData("field");
|
||||
AMO.getAddonId = function () { return page_state.addon_id };
|
||||
AMO.getReportName = function () { return page_state.report_name };
|
||||
AMO.getSeriesList = function () {
|
||||
return AMO.seriesList || {"metric" : reportName, fields : ["count"]};
|
||||
return {
|
||||
"metric": page_state.report_name,
|
||||
"fields": page_state.chart_fields
|
||||
}
|
||||
};
|
||||
AMO.getStatsBaseURL = function () { return stats_base_url };
|
||||
|
||||
t.go();
|
||||
|
||||
|
@ -39,8 +51,13 @@ $(document).ready(function () {
|
|||
if (newRange == "custom") {
|
||||
$customRangeForm.removeClass("hidden").slideDown('fast');
|
||||
} else {
|
||||
page_state.data_range = newRange;
|
||||
$customRangeForm.slideUp('fast');
|
||||
AMO.StatsManager.getSeries(AMO.getSeriesList(), newRange, updateSeries);
|
||||
AMO.StatsManager.getSeries(AMO.getSeriesList(), page_state.data_range, updateSeries);
|
||||
if (AMO.aggregate_stats_field) {
|
||||
show_aggregate_stats(AMO.aggregate_stats_field, page_state.data_range);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
|
@ -50,24 +67,53 @@ $(document).ready(function () {
|
|||
var start = new Date($("#date-range-start").val());
|
||||
var end = new Date($("#date-range-end").val());
|
||||
|
||||
range = {
|
||||
page_state.data_range = {
|
||||
custom: true,
|
||||
start: start,
|
||||
end: end
|
||||
};
|
||||
|
||||
generateSeries(report, range, updateSeries);
|
||||
generateSeries(report, page_state.data_range, updateSeries);
|
||||
});
|
||||
|
||||
t.lap("events init");
|
||||
|
||||
var csv_table_el = $(".csv-table");
|
||||
if (csv_table_el.length) {
|
||||
csvTable = new PageTable(csv_table_el[0]);
|
||||
}
|
||||
if (report == "overview") {
|
||||
|
||||
page_state.report_name = 'downloads';
|
||||
|
||||
var series_menu = $("#series-select");
|
||||
|
||||
t.lap("csvtable init");
|
||||
series_menu.click(function(e) {
|
||||
var $target = $(e.target);
|
||||
var new_report = $target.getData("report");
|
||||
var new_series = $target.getData("series");
|
||||
|
||||
if (new_series && new_report != AMO.getReportName()) {
|
||||
series_menu.children("li.selected").removeClass("selected");
|
||||
$target.parent().addClass("selected");
|
||||
|
||||
page_state.report_name = new_report;
|
||||
page_state.data_fields = new_series;
|
||||
|
||||
AMO.StatsManager.getSeries(AMO.getSeriesList(), page_state.data_range, initCharts);
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
// generate_top_charts();
|
||||
|
||||
initTopCharts();
|
||||
|
||||
} else {
|
||||
|
||||
var csv_table_el = $(".csv-table");
|
||||
if (csv_table_el.length) {
|
||||
csvTable = new PageTable(csv_table_el[0]);
|
||||
}
|
||||
|
||||
t.lap("csvtable init");
|
||||
|
||||
}
|
||||
|
||||
LoadBar.on("Loading the latest data…");
|
||||
//Get initial dataset
|
||||
|
@ -76,16 +122,21 @@ $(document).ready(function () {
|
|||
} else {
|
||||
var fetchStart = ago("30 days");
|
||||
}
|
||||
AMO.StatsManager._fetchData(report, fetchStart, today(), function () {
|
||||
t.go("fetching data")
|
||||
|
||||
AMO.StatsManager.getDataRange(AMO.getReportName(), fetchStart, today(), function () {
|
||||
t.lap("building aggregate stats")
|
||||
|
||||
if (AMO.aggregate_stats_field) {
|
||||
show_aggregate_stats(AMO.aggregate_stats_field, 30);
|
||||
show_aggregate_stats(AMO.aggregate_stats_field, page_state.data_range);
|
||||
}
|
||||
t.lap("building initial chart stuff")
|
||||
AMO.StatsManager.getSeries(AMO.getSeriesList(), "30 days", initCharts);
|
||||
LoadBar.off();
|
||||
csvTable.gotoPage(1);
|
||||
});
|
||||
|
||||
//initTopCharts();
|
||||
if (csvTable) {
|
||||
csvTable.gotoPage(1);
|
||||
}
|
||||
}, {force: true});
|
||||
|
||||
});
|
||||
|
||||
|
@ -123,14 +174,17 @@ $(document).ready(function () {
|
|||
var t = new Timer();
|
||||
|
||||
function dbg() {
|
||||
if(window.console && console.log) {
|
||||
console.log(Array.prototype.slice.apply(arguments));
|
||||
if(window.console && window.console.log) {
|
||||
window.console.log(Array.prototype.slice.apply(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
function updateSeries(cfg) {
|
||||
for (var i=0; i<cfg.length; i++) {
|
||||
mainChart.get(cfg[i].id).setData(cfg[i].data);
|
||||
var series = mainChart.get(cfg[i].id);
|
||||
if (series) {
|
||||
series.setData(cfg[i].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +203,9 @@ $(document).ready(function () {
|
|||
|
||||
|
||||
function initCharts(cfg) {
|
||||
t.lap("pre-charts");
|
||||
if (mainChart) {
|
||||
mainChart.destroy();
|
||||
}
|
||||
mainChart = new Highcharts.Chart({
|
||||
chart: {
|
||||
renderTo: 'head-chart',
|
||||
|
@ -205,7 +261,6 @@ $(document).ready(function () {
|
|||
|
||||
series: cfg
|
||||
});
|
||||
t.lap("charts init");
|
||||
|
||||
}
|
||||
|
||||
|
@ -285,10 +340,17 @@ function initTopCharts() {
|
|||
});
|
||||
}
|
||||
|
||||
function show_aggregate_stats (field, size) {
|
||||
AMO.StatsManager.getSum(field, ago((size * 3) + ' days'), ago((size * 2 - 1) + ' days'), function(sum_3x_range) {
|
||||
AMO.StatsManager.getSum(field, ago((size * 2) + ' days'), ago((size - 1) + ' days'), function(sum_prev_range) {
|
||||
AMO.StatsManager.getSum(field, ago(size + ' days'), today(), function(sum_range) {
|
||||
function show_aggregate_stats (_field, range) {
|
||||
field = {
|
||||
metric: AMO.getReportName(),
|
||||
name: _field
|
||||
}
|
||||
$(".stats-aggregate .range").text("Last " + range);
|
||||
$(".stats-aggregate .prev_range").text("Prior " + range);
|
||||
|
||||
AMO.StatsManager.getSum(field, ago(range, 3), ago(range, 2) + millis("1 day"), function(sum_3x_range) {
|
||||
AMO.StatsManager.getSum(field, ago(range, 2), ago(range) + millis("1 day"), function(sum_prev_range) {
|
||||
AMO.StatsManager.getSum(field, ago(range), today(), function(sum_range) {
|
||||
|
||||
$("#sum_range").text(Highcharts.numberFormat(sum_range, 0));
|
||||
$("#sum_prev_range").text(Highcharts.numberFormat(sum_prev_range, 0));
|
||||
|
@ -297,9 +359,9 @@ function show_aggregate_stats (field, size) {
|
|||
draw_diff($("#sum_prev_diff"), sum_prev_range, sum_3x_range);
|
||||
|
||||
|
||||
AMO.StatsManager.getMean(field, ago((size * 3) + ' days'), ago((size * 2 - 1) + ' days'), function(mean_3x_range) {
|
||||
AMO.StatsManager.getMean(field, ago((size * 2) + ' days'), ago((size - 1) + ' days'), function(mean_prev_range) {
|
||||
AMO.StatsManager.getMean(field, ago(size + ' days'), today(), function(mean_range) {
|
||||
AMO.StatsManager.getMean(field, ago(range, 3), ago(range, 2) + millis("1 day"), function(mean_3x_range) {
|
||||
AMO.StatsManager.getMean(field, ago(range, 2), ago(range) + millis("1 day"), function(mean_prev_range) {
|
||||
AMO.StatsManager.getMean(field, ago(range), today(), function(mean_range) {
|
||||
|
||||
$("#mean_range").text(Highcharts.numberFormat(mean_range, 0));
|
||||
$("#mean_prev_range").text(Highcharts.numberFormat(mean_prev_range, 0));
|
||||
|
@ -314,5 +376,4 @@ function show_aggregate_stats (field, size) {
|
|||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// (function () {
|
||||
|
||||
|
||||
// Versioning for offline storage
|
||||
var version = "1";
|
||||
var version = "2";
|
||||
|
||||
// where all the time-series data for the page is kept
|
||||
var datastore = {};
|
||||
|
@ -13,8 +13,17 @@
|
|||
maxdate: today()
|
||||
};
|
||||
|
||||
var writeInterval = false;
|
||||
var page_state = {
|
||||
}
|
||||
|
||||
|
||||
var capabilities = {
|
||||
localStorage : ('localStorage' in window) && window['localStorage'] !== null,
|
||||
JSON : window.JSON && typeof JSON.parse == 'function'
|
||||
};
|
||||
|
||||
var writeInterval = false;
|
||||
|
||||
LoadBar = {
|
||||
bar : $("#lm"),
|
||||
msg : $("#lm span"),
|
||||
|
@ -29,14 +38,14 @@
|
|||
LoadBar.bar.removeClass("on");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// date management helpers
|
||||
|
||||
var _millis = {
|
||||
"day" : 1000 * 60 * 60 * 24,
|
||||
"week" : 1000 * 60 * 60 * 24 * 7
|
||||
};
|
||||
|
||||
|
||||
function millis(str) {
|
||||
var tokens = str.split(/\s+/);
|
||||
n = parseInt(tokens[0]);
|
||||
|
@ -54,65 +63,74 @@
|
|||
return Date.parse([d.getFullYear(), pad2(d.getMonth()+1), pad2(d.getDate()+1)].join('-'));
|
||||
}
|
||||
|
||||
function ago (str) {
|
||||
return today() - millis(str);
|
||||
function ago (str, times) {
|
||||
times = (times !== undefined) ? times : 1;
|
||||
return today() - millis(str) * times;
|
||||
}
|
||||
|
||||
function chunkfor(start, end, step, chunk_size, inner, callback, ctx) {
|
||||
var position = start;
|
||||
|
||||
|
||||
|
||||
/* cfg takes:
|
||||
* start: the initial value
|
||||
* end: the (non-inclusive) max value
|
||||
* step: value to iterate by
|
||||
* chunk-size: how many iterations before setTimeout
|
||||
* inner: function to perform each iteration
|
||||
* callback: function to perform when finished
|
||||
* ctx: context from which to run all functions
|
||||
*/
|
||||
function chunkfor(cfg) {
|
||||
var position = cfg.start;
|
||||
|
||||
function nextchunk() {
|
||||
if (position < end) {
|
||||
|
||||
if (position < cfg.end) {
|
||||
|
||||
for (var iterator = position;
|
||||
iterator < position+(chunk_size*step) && iterator < end;
|
||||
iterator += step) {
|
||||
|
||||
inner.call(ctx, iterator);
|
||||
iterator < position+(cfg.chunk_size*cfg.step) && iterator < cfg.end;
|
||||
iterator += cfg.step) {
|
||||
|
||||
cfg.inner.call(cfg.ctx, iterator);
|
||||
}
|
||||
|
||||
position += chunk_size * step;
|
||||
|
||||
|
||||
position += cfg.chunk_size * cfg.step;
|
||||
|
||||
setTimeout( function () {
|
||||
nextchunk.call(this);
|
||||
}, 0);
|
||||
|
||||
|
||||
} else {
|
||||
callback.call(ctx);
|
||||
cfg.callback.call(cfg.ctx);
|
||||
}
|
||||
}
|
||||
nextchunk();
|
||||
}
|
||||
|
||||
|
||||
document.onbeforeunload = function () {
|
||||
AMO.StatsManager.write_local();
|
||||
}
|
||||
|
||||
|
||||
AMO.StatsManager = {
|
||||
|
||||
|
||||
init: function () {
|
||||
if (window.globalStorage) {
|
||||
var host = location.hostname;
|
||||
var local_store = globalStorage[host];
|
||||
if (capabilities.localStorage) {
|
||||
var local_store = localStorage;
|
||||
dbg("looking for local data");
|
||||
if (local_store.getItem("statscache") && AMO.StatsManager.verify_local()) {
|
||||
var cacheObject = local_store.getItem("statscache");
|
||||
dbg("found local data, loading...");
|
||||
datastore = JSON.parse(cacheObject);
|
||||
dbg(datastore);
|
||||
}
|
||||
} else {
|
||||
dbg("no local storage");
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
write_local: function () {
|
||||
dbg("saving local data");
|
||||
if (window.globalStorage) {
|
||||
if (capabilities.localStorage) {
|
||||
dbg("user has local storage");
|
||||
var host = location.hostname;
|
||||
var local_store = globalStorage[host];
|
||||
var local_store = localStorage;
|
||||
local_store.setItem("statscache", JSON.stringify(datastore));
|
||||
local_store.setItem("stats_version", version);
|
||||
dbg("saved local data");
|
||||
} else {
|
||||
dbg("no local storage");
|
||||
|
@ -120,19 +138,17 @@
|
|||
},
|
||||
|
||||
clear_local: function () {
|
||||
if (globalStorage) {
|
||||
var host = location.hostname;
|
||||
var local_store = globalStorage[host];
|
||||
if (capabilities.localStorage) {
|
||||
var local_store = localStorage;
|
||||
local_store.removeItem("statscache");
|
||||
dbg("cleared local data");
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
verify_local: function () {
|
||||
if (window.globalStorage) {
|
||||
var host = location.hostname;
|
||||
var local_store = globalStorage[host];
|
||||
if (local_store.getItem("stats_version") == version) {
|
||||
if (capabilities.localStorage) {
|
||||
var local_store = localStorage;
|
||||
if (local_store.getItem("stats_version") === version) {
|
||||
return true;
|
||||
} else {
|
||||
dbg("wrong offline data verion");
|
||||
|
@ -141,23 +157,26 @@
|
|||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
_fetchData: function (metric, start, end, callback) {
|
||||
|
||||
|
||||
var seriesStart = start;
|
||||
var seriesEnd = end;
|
||||
|
||||
var seriesURLStart = Highcharts.dateFormat('%Y%m%d', seriesStart);
|
||||
var seriesURLEnd = Highcharts.dateFormat('%Y%m%d', seriesEnd);
|
||||
var seriesURL = AMO.getStatsBaseURL() + ([metric,"day",seriesURLStart,seriesURLEnd]).join("-") + ".json";
|
||||
var seriesURLStart = Highcharts.dateFormat('%Y%m%d', seriesStart),
|
||||
seriesURLEnd = Highcharts.dateFormat('%Y%m%d', seriesEnd),
|
||||
seriesURL = AMO.getStatsBaseURL() + ([metric,"day",seriesURLStart,seriesURLEnd]).join("-") + ".json";
|
||||
|
||||
$.get(seriesURL, function(data, status, xhr) {
|
||||
|
||||
|
||||
$.ajax({ url: seriesURL,
|
||||
dataType: 'text',
|
||||
success: function(raw_data, status, xhr) {
|
||||
|
||||
var maxdate = 0,
|
||||
mindate = today();
|
||||
|
||||
|
||||
if (xhr.status == 200) {
|
||||
|
||||
|
||||
if (!datastore[metric]) {
|
||||
datastore[metric] = {};
|
||||
datastore[metric].mindate = today();
|
||||
|
@ -165,59 +184,75 @@
|
|||
}
|
||||
|
||||
var ds = datastore[metric];
|
||||
|
||||
// process the Data. We want to directly use the native JSON
|
||||
// without jQuery's costly regexes if we can.
|
||||
if (capabilities.JSON) {
|
||||
dbg("native JSON");
|
||||
var data = JSON.parse(raw_data);
|
||||
} else {
|
||||
dbg("jQuery JSON");
|
||||
var data = $.parseJSON(raw_data);
|
||||
}
|
||||
|
||||
chunkfor(0, data.length, 1, 10,
|
||||
function (i) {
|
||||
var datekey = Date.parse(data[i].date);
|
||||
|
||||
maxdate = Math.max(datekey, ds.maxdate);
|
||||
mindate = Math.min(datekey, ds.mindate);
|
||||
|
||||
chunkfor({
|
||||
start: 0,
|
||||
end: data.length,
|
||||
step: 1,
|
||||
chunk_size: 10,
|
||||
inner: function (i) {
|
||||
var datekey = parseInt(Date.parse(data[i].date));
|
||||
maxdate = Math.max(datekey, maxdate);
|
||||
mindate = Math.min(datekey, mindate);
|
||||
ds[datekey] = data[i];
|
||||
},
|
||||
function () {
|
||||
ds.maxdate = Math.max(maxdate, ds.maxdate);
|
||||
ds.mindate = Math.min(mindate, ds.mindate);
|
||||
callback: function () {
|
||||
ds.maxdate = Math.max(parseInt(maxdate), parseInt(ds.maxdate));
|
||||
ds.mindate = Math.min(parseInt(mindate), parseInt(ds.mindate));
|
||||
callback.call(this, true);
|
||||
clearTimeout(writeInterval);
|
||||
writeInterval = setTimeout(AMO.StatsManager.write_local, 2000);
|
||||
}, this
|
||||
);
|
||||
},
|
||||
ctx: this
|
||||
});
|
||||
|
||||
|
||||
} else if (xhr.status == 202) {
|
||||
|
||||
|
||||
var retry_delay = 30000;
|
||||
|
||||
|
||||
if (xhr.getResponseHeader("Retry-After")) {
|
||||
retry_delay = parseInt(xhr.getResponseHeader("Retry-After")) * 1000;
|
||||
}
|
||||
|
||||
|
||||
setTimeout(function () {
|
||||
AMO.StatsManager._fetchData(metric, start, end, callback);
|
||||
}, retry_delay);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}});
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* getDataRange: ensures we have all the data from the server we need,
|
||||
* and queues up requests to the server if the requested data is outside
|
||||
* the range currently stored locally. Once all server requests return,
|
||||
* we move on.
|
||||
*/
|
||||
|
||||
getDataRange: function (metric, start, end, callback, quiet) {
|
||||
var needed = 0;
|
||||
|
||||
|
||||
getDataRange: function (metric, start, end, callback, opts) {
|
||||
var needed = 0,
|
||||
opts = opts || {};
|
||||
quiet = opts.quiet || false,
|
||||
force = opts.force || false;
|
||||
|
||||
end = Math.min(end, range_limits.maxdate);
|
||||
|
||||
function finished() {
|
||||
needed--;
|
||||
if (datastore[metric].maxdate < end) {
|
||||
if (datastore[metric] && datastore[metric].maxdate < end) {
|
||||
dbg("truncating fetchable range");
|
||||
range_limits.maxdate = datastore[metric].maxdate;
|
||||
}
|
||||
|
@ -228,8 +263,8 @@
|
|||
if (!quiet) LoadBar.on("Loading…");
|
||||
}
|
||||
}
|
||||
|
||||
if (datastore[metric]) {
|
||||
|
||||
if (datastore[metric] && !force) {
|
||||
ds = datastore[metric];
|
||||
if (ds.maxdate < end) {
|
||||
needed++;
|
||||
|
@ -243,10 +278,10 @@
|
|||
needed++;
|
||||
AMO.StatsManager._fetchData(metric, start, end, finished);
|
||||
}
|
||||
|
||||
|
||||
finished();
|
||||
},
|
||||
|
||||
|
||||
getSeries: function (seriesList, time, callback) {
|
||||
metric = seriesList.metric;
|
||||
if (typeof time == "string") {
|
||||
|
@ -270,30 +305,31 @@
|
|||
} else {
|
||||
|
||||
AMO.StatsManager.getDataRange(metric, seriesStart, seriesEnd, function() {
|
||||
|
||||
var out = {};
|
||||
|
||||
var fields = seriesList.fields;
|
||||
|
||||
var data = datastore[metric];
|
||||
|
||||
for (var j=0; j<fields.length; j++) {
|
||||
out[fields[j]] = [];
|
||||
}
|
||||
|
||||
chunkfor(seriesStart, seriesEnd, millis("1 day"), 10,
|
||||
function (i) {
|
||||
chunkfor({
|
||||
start: seriesStart,
|
||||
end: seriesEnd,
|
||||
step: millis("1 day"),
|
||||
chunk_size: 10,
|
||||
inner: function (i) {
|
||||
for (var j=0; j<fields.length; j++) {
|
||||
var val = data[i] ? AMO.StatsManager.getField(data[i], fields[j]) : null;
|
||||
var point = {
|
||||
x : i,
|
||||
y : data[i] ? parseFloat(AMO.StatsManager.getField(data[i], fields[j])) : null
|
||||
y : val ? parseFloat(val) : null
|
||||
};
|
||||
out[fields[j]].push(point);
|
||||
}
|
||||
},
|
||||
function () {
|
||||
callback: function () {
|
||||
var ret = [];
|
||||
|
||||
for (var j=0; j<fields.length; j++) {
|
||||
ret.push({
|
||||
type: 'line',
|
||||
|
@ -301,34 +337,27 @@
|
|||
data: out[fields[j]]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
seriesCache[cacheKey] = ret;
|
||||
|
||||
callback.call(this, ret);
|
||||
}
|
||||
);
|
||||
|
||||
},
|
||||
ctx: this
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
getPage: function(metric, num, callback, size) {
|
||||
|
||||
size = size || 14;
|
||||
|
||||
var cacheKey = metric + "_page_" + num + "_by_" + size;
|
||||
|
||||
|
||||
if (seriesCache[cacheKey]) {
|
||||
|
||||
if (!seriesCache[cacheKey].nodata) {
|
||||
callback.call(this, seriesCache[cacheKey]);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var ds = datastore[metric];
|
||||
|
||||
|
||||
var seriesEnd = ds.maxdate - size * (num - 1) * millis("1 day");
|
||||
|
||||
|
||||
|
@ -337,15 +366,15 @@
|
|||
var dataStart = seriesStart - size * millis("1 day");
|
||||
|
||||
AMO.StatsManager.getDataRange(metric, dataStart, seriesEnd, function() {
|
||||
|
||||
|
||||
var ret = [];
|
||||
|
||||
|
||||
ret.page = num;
|
||||
|
||||
|
||||
for (var i=seriesEnd; i>seriesStart; i-= millis("1 day")) {
|
||||
if (ds[i] !== undefined) ret.push(ds[i]);
|
||||
}
|
||||
|
||||
|
||||
if (ret.length) {
|
||||
seriesCache[cacheKey] = ret;
|
||||
|
||||
|
@ -353,35 +382,35 @@
|
|||
} else {
|
||||
seriesCache[cacheKey] = {nodata:true};
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
getNumPages: function(metric, size) {
|
||||
size = size || 14;
|
||||
|
||||
|
||||
var ds = datastore[metric];
|
||||
|
||||
|
||||
return Math.ceil((ds.maxdate - ds.mindate) / millis("1 day") / size);
|
||||
},
|
||||
|
||||
|
||||
getSum: function(field, start, end, callback, name) {
|
||||
var metric = field.metric;
|
||||
var cacheKey = name || (metric + field.name + "_sum_" + start + "_" + end);
|
||||
|
||||
|
||||
if (seriesCache[cacheKey]) {
|
||||
callback.call(this, seriesCache[cacheKey]);
|
||||
} else {
|
||||
AMO.StatsManager.getDataRange(metric, start, end, function () {
|
||||
var ds = datastore[metric];
|
||||
|
||||
|
||||
var sum = 0;
|
||||
|
||||
|
||||
var nodata = true;
|
||||
|
||||
|
||||
for (var i=start; i<end; i+= millis("1 day")) {
|
||||
if (ds[i] !== undefined) {
|
||||
var datum = AMO.StatsManager.getField(ds[i], field.name);
|
||||
|
@ -391,24 +420,24 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nodata) {
|
||||
var ret = {nodata: true};
|
||||
} else {
|
||||
var ret = sum;
|
||||
}
|
||||
|
||||
|
||||
seriesCache[cacheKey] = ret;
|
||||
|
||||
|
||||
callback.call(this, ret);
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
getMean: function(field, start, end, callback) {
|
||||
var metric = field.metric;
|
||||
|
||||
|
||||
AMO.StatsManager.getSum(field, start, end, function (sum) {
|
||||
if (sum.nodata) {
|
||||
callback.call(this, sum);
|
||||
|
@ -417,26 +446,29 @@
|
|||
callback.call(this, mean);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
getStat: function(name) {
|
||||
return seriesCache[name] || {nodata: true};
|
||||
},
|
||||
|
||||
|
||||
getField: function(record, field) {
|
||||
|
||||
var parts = field.split('|');
|
||||
var val = record;
|
||||
|
||||
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
val = val[parts[i]];
|
||||
if (!val) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
// })();
|
|
@ -73,8 +73,6 @@ function PageTable(_el) {
|
|||
|
||||
//Set up a BarTable if needed
|
||||
|
||||
dbg(barColumns);
|
||||
|
||||
if (barColumns.length) {
|
||||
this.barTable = new BarTable({
|
||||
el: this.tableEl,
|
||||
|
@ -149,8 +147,6 @@ PageTable.prototype.addPage = function (data) {
|
|||
|
||||
t.lap('done page');
|
||||
|
||||
console.log(page.html());
|
||||
|
||||
this.pages[data.page] = page;
|
||||
this.tableEl.append(page);
|
||||
if (this.barTable) {
|
||||
|
|
3
urls.py
3
urls.py
|
@ -38,9 +38,6 @@ urlpatterns = patterns('',
|
|||
# Search
|
||||
('^search/', include('search.urls')),
|
||||
|
||||
# Stats
|
||||
('^stats/', include('stats.urls')),
|
||||
|
||||
# Global stats dashboard.
|
||||
url('^statistics/', lambda r: redirect('/'), name='statistics.dashboard'),
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче