diff --git a/stackalytics/dashboard/decorators.py b/stackalytics/dashboard/decorators.py index 27b027a30..0724b3ef3 100644 --- a/stackalytics/dashboard/decorators.py +++ b/stackalytics/dashboard/decorators.py @@ -247,6 +247,13 @@ def record_filter(ignore=None): record_ids, _filter_records_by_days(start_date, end_date, memory_storage_inst)) + # filtering by non-indexed attributes goes last + language = params['language'] + if language: + record_ids = ( + set(memory_storage_inst.get_record_ids_by_languages( + record_ids, language))) + kwargs['record_ids'] = record_ids kwargs['records'] = memory_storage_inst.get_records(record_ids) @@ -454,6 +461,9 @@ def templated(template=None, return_code=200): ctx['user_inst'] = vault.get_user_from_runtime_storage( ctx['user_id']) + ctx['language'] = parameters.get_single_parameter( + kwargs, 'language') + ctx['page_title'] = helpers.make_page_title( ctx['project_type_inst'], ctx.get('release'), ctx.get('module_inst'), diff --git a/stackalytics/dashboard/memory_storage.py b/stackalytics/dashboard/memory_storage.py index ee29bbac3..da2d63ee0 100644 --- a/stackalytics/dashboard/memory_storage.py +++ b/stackalytics/dashboard/memory_storage.py @@ -188,6 +188,14 @@ class CachedMemoryStorage(MemoryStorage): def get_first_record_day(self): return min(self.day_index.keys()) + def get_record_ids_by_languages(self, record_ids, languages): + # special case: filter by attribute not covered by index + for record in self.get_records(record_ids): + lng = record.value + if lng: + if lng.lower() in languages: + yield record.record_id + def get_memory_storage(memory_storage_type): if memory_storage_type == MEMORY_STORAGE_CACHED: diff --git a/stackalytics/dashboard/parameters.py b/stackalytics/dashboard/parameters.py index cae6cd7f6..fff7074f2 100644 --- a/stackalytics/dashboard/parameters.py +++ b/stackalytics/dashboard/parameters.py @@ -58,7 +58,7 @@ METRIC_TO_RECORD_TYPE = { FILTER_PARAMETERS = ['release', 'project_type', 'module', 'company', 'user_id', 'metric', 'start_date', 'end_date', 'blueprint_id', - 'core_in'] + 'core_in', 'language'] DEFAULT_RECORDS_LIMIT = 10 DEFAULT_STATIC_ACTIVITY_SIZE = 100 diff --git a/stackalytics/dashboard/templates/overview.html b/stackalytics/dashboard/templates/overview.html index ff60b37ac..1c9e03a5c 100644 --- a/stackalytics/dashboard/templates/overview.html +++ b/stackalytics/dashboard/templates/overview.html @@ -127,6 +127,39 @@ {% block right_frame %} + {% if show_languages_breakdown %} +
+ {% if language %} +
+ + +
+ + {% else %} +

Languages

+ +
+ + + + + + + + + + + +
#LanguageTranslations
+ {% endif %} +
+
+ {% endif %} + {% if show_module_breakdown %}

Contribution by modules

@@ -179,27 +212,6 @@
{% endif %} - {% if show_languages_breakdown %} -
-

Languages

- -
- - - - - - - - - - - -
#LanguageTranslations
-
-
- {% endif %} - {% if show_contribution_on_right %} {{ contribution_summary.show_contribution_summary(show_all=False) }} {{ show_report_links(module, company, user_id) }} diff --git a/stackalytics/dashboard/web.py b/stackalytics/dashboard/web.py index 069d31aed..a72ae6ba1 100644 --- a/stackalytics/dashboard/web.py +++ b/stackalytics/dashboard/web.py @@ -403,12 +403,26 @@ def get_bpd(records, **kwargs): return result +@app.route('/api/1.0/languages') +@decorators.exception_handler() +@decorators.response() +@decorators.cached(ignore=['language']) +@decorators.jsonify() +@decorators.record_filter(ignore=['language']) +def get_languages_json(record_ids, **kwargs): + memory_storage = vault.get_memory_storage() + languages = set(r.value for r in memory_storage.get_records(record_ids)) + + return [{'id': c.lower().replace('&', ''), 'text': c} + for c in sorted(languages)] + + @app.route('/api/1.0/stats/languages') @decorators.exception_handler() @decorators.response() @decorators.cached() @decorators.jsonify('stats') -@decorators.record_filter() +@decorators.record_filter(ignore=['language']) def get_languages(records, **kwargs): result = [] languages = collections.defaultdict(int)