diff --git a/dashboard/decorators.py b/dashboard/decorators.py index 467fcda82..87244a6f4 100644 --- a/dashboard/decorators.py +++ b/dashboard/decorators.py @@ -397,7 +397,14 @@ def jsonify(root='data'): def decorator(func): @functools.wraps(func) def jsonify_decorated_function(*args, **kwargs): - return json.dumps({root: func(*args, **kwargs)}) + value = func(*args, **kwargs) + if isinstance(value, tuple): + result = dict([(root[i], value[i]) + for i in six.moves.range(min(len(value), + len(root)))]) + else: + result = {root: value} + return json.dumps(result) return jsonify_decorated_function diff --git a/dashboard/static/css/style.css b/dashboard/static/css/style.css index 0e5f531f2..4d17e4951 100644 --- a/dashboard/static/css/style.css +++ b/dashboard/static/css/style.css @@ -470,3 +470,13 @@ div.stackamenu li.current-menu-item a span { color: white; /*text-shadow: 0 -1px 0 #436281;*/ } + +.select2-loading { + font-style: italic; + color: dimgray; + background: url('../images/select2-spinner.gif') no-repeat 100% !important; +} + +.ui-widget-overlay { + opacity: 0.6; +} diff --git a/dashboard/static/js/driverlog-ui.js b/dashboard/static/js/driverlog-ui.js index 0302258b7..28344b66c 100644 --- a/dashboard/static/js/driverlog-ui.js +++ b/dashboard/static/js/driverlog-ui.js @@ -36,132 +36,66 @@ function make_uri(uri, options) { return (str == "") ? uri : uri + "?" + str; } -function make_std_options() { - var options = {}; - options['project_id'] = $('#project_selector').val(); - options['vendor'] = $('#vendor_selector').val(); - options['release_id'] = $('#release_selector').val(); - - return options; +function getPageState() { + return { + project_id: $('#project_id').val(), + vendor: $('#vendor').val(), + release_id: $('#release_id').val() + }; } -function reload() { - var ops = {}; - $.extend(ops, getUrlVars()); - $.extend(ops, make_std_options()); - window.location.search = $.map(ops,function (val, index) { - return index + "=" + encodeURIComponent(val); +function reload(extra) { + window.location.search = $.map($.extend(getPageState(), extra), function (val, index) { + return val? (index + "=" + encodeURIComponent(val)) : null; }).join("&") } -function init_selectors(base_url) { - $(document).tooltip(); +function initSelectors(base_url) { - var project_id = getUrlVars()["project_id"]; + function initSingleSelector(name, data_container, api_url, select2_extra_options, change_handler) { + $("#" + name).val(0).select2({ + data: [{id: 0, text: "Loading..." }], + formatSelection: function(item) { return "
" + item.text + "
"} + }).select2("enable", false); - $("#project_selector").val(project_id).select2({ - allowClear: true, - placeholder: "Select Project", - ajax: { - url: make_uri(base_url + "api/1.0/list/project_ids"), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - return {results: data["project_ids"]}; + $.ajax({ + url: api_url, + dataType: "jsonp", + success: function (data) { + var initial_value = getUrlVars()[name]; + if (!initial_value && data["default"]) { + initial_value = data["default"]; + } + $("#" + name). + val(initial_value). + select2($.extend({ + data: data[data_container] + }, select2_extra_options)). + on("select2-selecting",function (e) { /* don't use 'change' event, because it changes value and then refreshes the page */ + var options = {}; + options[name] = e.val; + if (change_handler) { + change_handler(options); + console.log(options); + } + reload(options); + }). + on("select2-removed",function (e) { + var options = {}; + options[name] = ''; + reload(options); + }). + select2("enable", true); } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - if (id !== "") { - $.ajax(make_uri(base_url + "api/1.0/list/project_ids/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["project_id"]); - }); - } - } - }); - - $('#project_selector') - .on("change", function (e) { - reload(); - }); - - var vendor = getUrlVars()["vendor"]; - - $("#vendor_selector").val(vendor).select2({ - allowClear: true, - placeholder: "Select Vendor", - ajax: { - url: make_uri(base_url + "api/1.0/list/vendors"), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - return {results: data["vendors"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - if (id !== "") { - $.ajax(make_uri(base_url + "api/1.0/list/vendors/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["vendor"]); - }); - } - } - }); - - $('#vendor_selector') - .on("change", function (e) { - reload(); - }); - - var release_id = getUrlVars()["release_id"]; - - $("#release_selector").val(release_id).select2({ - allowClear: true, - placeholder: "Select Release", - ajax: { - url: make_uri(base_url + "api/1.0/list/releases"), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - return {results: data["releases"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - if (id !== "") { - $.ajax(make_uri(base_url + "api/1.0/list/releases/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["release"]); - }); - } - } - }); - - $('#release_selector') - .on("change", function (e) { - reload(); }); + } + initSingleSelector("project_id", "project_ids", make_uri(base_url + "api/1.0/list/project_ids"), {allowClear: true}); + initSingleSelector("vendor", "vendors", make_uri(base_url + "api/1.0/list/vendors"), {allowClear: true}); + initSingleSelector("release", "releases", make_uri(base_url + "api/1.0/list/releases"), {allowClear: true}); } -function show_driver_info(driver) { +function showDriverInfo(driver) { $("#driver_info_container").empty(); $("#driver_info_template").tmpl(driver).appendTo("#driver_info_container"); @@ -194,7 +128,7 @@ function show_driver_info(driver) { $("#driver_info_dialog").dialog("open"); } -function setup_driver_info_handler(table_id, element_id, driver) { +function setupDriverInfoHandler(table_id, element_id, driver) { $("#driver_info_dialog").dialog({ autoOpen: false, width: "70%", @@ -212,11 +146,11 @@ function setup_driver_info_handler(table_id, element_id, driver) { event.preventDefault(); event.stopPropagation(); - show_driver_info(driver); + showDriverInfo(driver); }); } -function show_summary(base_url) { +function showSummary(base_url) { var table_column_names = ["project_name", "vendor", "driver_info", "in_trunk", "ci_tested", "maintainers_info"]; var table_id = "data_table"; @@ -240,7 +174,7 @@ function show_summary(base_url) { tableData[i].driver_info += "
" + tableData[i].description + "
"; } - setup_driver_info_handler(table_id, "driver_" + i, tableData[i]); + setupDriverInfoHandler(table_id, "driver_" + i, tableData[i]); var releases_list = []; for (var j = 0; j < tableData[i].releases_info.length; j++) { @@ -300,6 +234,7 @@ function show_summary(base_url) { ], "iDisplayLength": -1, "bAutoWidth": false, + "bPaginate": false, "aaData": tableData, "aoColumns": tableColumns }); diff --git a/dashboard/static/js/stackalytics-ui.js b/dashboard/static/js/stackalytics-ui.js index cb17a95ac..0bd10f06d 100644 --- a/dashboard/static/js/stackalytics-ui.js +++ b/dashboard/static/js/stackalytics-ui.js @@ -15,7 +15,7 @@ limitations under the License. */ -function createTimeline(data) { +function _createTimeline(data) { var plot = $.jqplot('timeline', data, { gridPadding: { right: 35 @@ -74,10 +74,10 @@ function createTimeline(data) { function renderTimeline(options) { $(document).ready(function () { $.ajax({ - url: make_uri("/api/1.0/stats/timeline", options), + url: makeURI("/api/1.0/stats/timeline", options), dataType: "json", success: function (data) { - createTimeline(data["timeline"]); + _createTimeline(data["timeline"]); } }); }); @@ -88,7 +88,7 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param, $(document).ready(function () { $.ajax({ - url: make_uri(url), + url: makeURI(url), dataType: "jsonp", success: function (data) { @@ -115,7 +115,7 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param, if (!data[i].link) { if (data[i].id) { - data[i].link = make_link(data[i].id, data[i].name, link_param); + data[i].link = makeLink(data[i].id, data[i].name, link_param); } else { data[i].link = data[i].name } @@ -180,7 +180,7 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param, }); } -function render_bar_chart(chart_id, chart_data) { +function renderBarChart(chart_id, chart_data) { $.jqplot(chart_id, chart_data, { seriesDefaults: { renderer: $.jqplot.BarRenderer, @@ -202,7 +202,7 @@ function render_bar_chart(chart_id, chart_data) { }); } -function render_punch_card(chart_id, chart_data) { +function renderPunchCard(chart_id, chart_data) { $.jqplot(chart_id, chart_data, { seriesDefaults:{ renderer: $.jqplot.BubbleRenderer, @@ -262,20 +262,20 @@ function extendWithGravatar(record, image_size) { function getUrlVars() { var vars = {}; - var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { + window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { vars[key] = decodeURIComponent(value); }); return vars; } -function make_link(id, title, param_name) { +function makeLink(id, title, param_name) { var options = {}; options[param_name] = encodeURIComponent(id).toLowerCase(); - var link = make_uri("/", options); + var link = makeURI("/", options); return "" + title + "" } -function make_uri(uri, options) { +function makeURI(uri, options) { var ops = {}; $.extend(ops, getUrlVars()); if (options != null) { @@ -288,234 +288,82 @@ function make_uri(uri, options) { return (str == "") ? uri : uri + "?" + str; } -function make_std_options() { - var options = {}; - options['release'] = $('#release').val(); - options['metric'] = $('#metric').val(); - options['project_type'] = $('#project_type').val(); - options['module'] = $('#module').val() || ''; - options['company'] = $('#company').val() || ''; - options['user_id'] = $('#user').val() || ''; - - return options; +function getPageState() { + return { + release: $('#release').val(), + project_type: $('#project_type').val(), + module: $('#module').val(), + company: $('#company').val(), + user_id: $('#user').val(), + metric: $('#metric').val() + }; } -function reload() { - window.location.search = $.map(make_std_options(),function (val, index) { - return index + "=" + encodeURIComponent(val); +function reload(extra) { + window.location.search = $.map($.extend(getUrlVars(), extra), function (val, index) { + return val? (index + "=" + encodeURIComponent(val)) : null; }).join("&") } -function init_selectors(base_url) { - var release = getUrlVars()["release"]; - if (!release) { - release = "_default"; - } - $("#release").val(release).select2({ - ajax: { - url: make_uri(base_url + "/api/1.0/releases"), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - return {results: data["releases"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - $.ajax(make_uri(base_url + "/api/1.0/releases/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["release"]); - $("#release").val(data["release"].id) - }); - } - }); - $('#release') - .on("change", function (e) { - reload(); - }); +function initSingleSelector(name, api_url, select2_extra_options, change_handler) { + var selectorId = "#" + name + "_selector"; - var metric = getUrlVars()["metric"]; - if (!metric) { - metric = "_default"; - } - $("#metric").val(metric).select2({ - ajax: { - url: make_uri(base_url + "/api/1.0/metrics"), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - return {results: data["metrics"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - $.ajax(make_uri(base_url + "/api/1.0/metrics/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["metric"]); - $("#metric").val(data["metric"].id); - }); + $(selectorId).val(0).select2({ + data: [ + {id: 0, text: "Loading..." } + ], + formatSelection: function (item) { + return "
" + item.text + "
" } - }); - $('#metric') - .on("change", function (e) { - reload(); - }); + }).select2("enable", false); - var project_type = getUrlVars()["project_type"]; - if (!project_type) { - project_type = "_default"; - } - $("#project_type").val(project_type).select2({ - ajax: { - url: make_uri(base_url + "/api/1.0/project_types"), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - const project_types = data["project_types"]; - var result = []; - for (var key in project_types) { - result.push({id: project_types[key].id, text: project_types[key].text, group: true}); - for (var i in project_types[key].items) { - var item = project_types[key].items[i]; - result.push({id: item.id, text: item.text}); + $.ajax({ + url: api_url, + dataType: "jsonp", + success: function (data) { + var initial_value = getUrlVars()[name]; + if (!initial_value && data["default"]) { + initial_value = data["default"]; + } + $(selectorId). + val(initial_value). + select2($.extend({ + data: data["data"] + }, select2_extra_options)). + on("select2-selecting",function (e) { /* don't use 'change' event, because it changes value and only after refreshes the page */ + var options = {}; + options[name] = e.val; + if (change_handler) { + change_handler(options); } - } - return {results: result}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - $.ajax(make_uri(base_url + "/api/1.0/project_types/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["project_type"]); - $("#project_type").val(data["project_type"].id); - }); - }, - formatResultCssClass: function (item) { - if (item.group) { - return "project_group" - } else { - return "project_group_item"; - } + reload(options); + }). + on("select2-removed",function (e) { + var options = {}; + options[name] = ''; + reload(options); + }). + select2("enable", true); } }); - $('#project_type') - .on("change", function (e) { - $('#module').val(''); - reload(); - }); - - $("#company").select2({ - allowClear: true, - ajax: { - url: make_uri(base_url + "/api/1.0/companies"), - dataType: 'jsonp', - data: function (term, page) { - return { - company_name: term - }; - }, - results: function (data, page) { - return {results: data["companies"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - if (id !== "") { - $.ajax(make_uri(base_url + "/api/1.0/companies/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["company"]); - }); - } - } - }); - - $('#company') - .on("change", function (e) { - reload(); - }); - - $("#module").select2({ - allowClear: true, - ajax: { - url: make_uri(base_url + "/api/1.0/modules", {tags: "module,program,group"}), - dataType: 'jsonp', - data: function (term, page) { - return { - query: term - }; - }, - results: function (data, page) { - return {results: data["modules"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - if (id !== "") { - $.ajax(make_uri(base_url + "/api/1.0/modules/" + id), { - dataType: "jsonp" - }).done(function (data) { - callback(data["module"]); - }); - } - }, - formatResultCssClass: function (item) { - if (item.tag) { - return "select_module_" + item.tag; - } - return ""; - } - }); - - $('#module') - .on("change", function (e) { - reload(); - }); - - $("#user").select2({ - allowClear: true, - ajax: { - url: make_uri(base_url + "/api/1.0/users"), - dataType: 'jsonp', - data: function (term, page) { - return { - user_name: term - }; - }, - results: function (data, page) { - return {results: data["users"]}; - } - }, - initSelection: function (element, callback) { - var id = $(element).val(); - if (id !== "") { - $.ajax(make_uri(base_url + "/api/1.0/users/" + id), { - dataType: "json" - }).done(function (data) { - callback(data["user"]); - }); - } - } - }); - - $('#user') - .on("change", function (e) { - reload(); - }); +} + +function initSelectors(base_url) { + initSingleSelector("release", makeURI(base_url + "/api/1.0/releases")); + initSingleSelector("project_type", makeURI(base_url + "/api/1.0/project_types"), { + formatResultCssClass: function (item) { + return (item.child) ? "project_group_item" : "project_group"; + } + }, function (options) { + options['module'] = null; + }); + initSingleSelector("module", makeURI(base_url + "/api/1.0/modules", {tags: "module,program,group"}), { + formatResultCssClass: function (item) { + return (item.tag)? ("select_module_" + item.tag): ""; + }, + allowClear: true + }); + initSingleSelector("company", makeURI(base_url + "/api/1.0/companies"), {allowClear: true}); + initSingleSelector("user_id", makeURI(base_url + "/api/1.0/users"), {allowClear: true}); + initSingleSelector("metric", makeURI(base_url + "/api/1.0/metrics")); } diff --git a/dashboard/templates/_macros/activity_log.html b/dashboard/templates/_macros/activity_log.html index c5f97a21f..b6b4a445b 100644 --- a/dashboard/templates/_macros/activity_log.html +++ b/dashboard/templates/_macros/activity_log.html @@ -23,7 +23,7 @@ show_record_type=True, show_user_gravatar=True, gravatar_size=32, show_all=True) $.extend(options, extra_options); $.ajax({ - url: make_uri("/api/1.0/activity", options), + url: makeURI("/api/1.0/activity", options), dataType: "json", success: function (data) { if (data["activity"].length < page_size) { @@ -33,7 +33,6 @@ show_record_type=True, show_user_gravatar=True, gravatar_size=32, show_all=True) $('#activity_header').hide(); } $.each(data["activity"], function() { - console.log(this); extendWithGravatar(this, {{ gravatar_size }}); }); $("#activity_template").tmpl(data["activity"]).appendTo("#activity_container"); diff --git a/dashboard/templates/_macros/contribution_summary.html b/dashboard/templates/_macros/contribution_summary.html index f1bd3239c..21eb67679 100644 --- a/dashboard/templates/_macros/contribution_summary.html +++ b/dashboard/templates/_macros/contribution_summary.html @@ -3,7 +3,7 @@ {% endblock %} diff --git a/dashboard/templates/reports/contribution.html b/dashboard/templates/reports/contribution.html index d4838b500..f6dd74279 100644 --- a/dashboard/templates/reports/contribution.html +++ b/dashboard/templates/reports/contribution.html @@ -30,7 +30,7 @@ Contribution into {{ module }} for the last {{ days }} days var table_id = "review_stats_table"; $.ajax({ - url: make_uri("/api/1.0/stats/engineers_extended?project_type=all&metric=marks&module={{ module }}&release=all&start_date={{ start_date }}"), + url: makeURI("/api/1.0/stats/engineers_extended?project_type=all&metric=marks&module={{ module }}&release=all&start_date={{ start_date }}"), dataType: "json", success: function (data) { var tableData = data["stats"]; @@ -57,8 +57,8 @@ Contribution into {{ module }} for the last {{ days }} days for (i = 0; i < tableData.length; i++) { if (tableData[i].id) { - var user_link = make_uri("/", {user_id: tableData[i].id, metric: "marks"}); - var company_link = make_uri("/", {company: tableData[i].company, metric: "marks"}); + var user_link = makeURI("/", {user_id: tableData[i].id, metric: "marks"}); + var company_link = makeURI("/", {company: tableData[i].company, metric: "marks"}); tableData[i].link = "" + tableData[i].name + "" + " " + "(" + tableData[i].company + ")" } else { diff --git a/dashboard/templates/reports/driverlog.html b/dashboard/templates/reports/driverlog.html index 8c09206dd..f42ea2dd8 100644 --- a/dashboard/templates/reports/driverlog.html +++ b/dashboard/templates/reports/driverlog.html @@ -29,7 +29,14 @@ - {% block scripts %}{% endblock %} + {% endblock %} @@ -53,31 +60,21 @@ - - -
- - + +
- - + +
- - + +
diff --git a/dashboard/templates/reports/members.html b/dashboard/templates/reports/members.html index bd082a52a..38f2ed3be 100644 --- a/dashboard/templates/reports/members.html +++ b/dashboard/templates/reports/members.html @@ -1,17 +1,52 @@ -{% extends "reports/base_report.html" %} +{% extends "base.html" %} -{% block title %} - OpenStack foundation members -{% endblock %} +{% block head %} + Members of OpenStack Foundation -{% block scripts %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -278,16 +295,6 @@ } -{% endblock %} - - -{% block content %} - - - +{% endblock %} + +{% block body %} + +
+
+
+ About ↗ +
+ + + +
+ data-placeholder="Any company"/>
@@ -403,4 +437,7 @@ +
+
+ {% endblock %} diff --git a/dashboard/templates/reports/open_reviews.html b/dashboard/templates/reports/open_reviews.html index 25ab645d8..752f9e5ff 100644 --- a/dashboard/templates/reports/open_reviews.html +++ b/dashboard/templates/reports/open_reviews.html @@ -7,8 +7,8 @@ Open reviews report for {{ module }} {% block scripts %} {% endblock %} diff --git a/dashboard/templates/reports/user_activity.html b/dashboard/templates/reports/user_activity.html index cb6b60e6a..3343602fd 100644 --- a/dashboard/templates/reports/user_activity.html +++ b/dashboard/templates/reports/user_activity.html @@ -10,7 +10,7 @@ {% block scripts %} {% endblock %} diff --git a/dashboard/templates/widget.html b/dashboard/templates/widget.html index e9a178999..f9b9e7c74 100644 --- a/dashboard/templates/widget.html +++ b/dashboard/templates/widget.html @@ -42,7 +42,7 @@ var base_url = "http://stackalytics.com"; $(document).ready(function () { - init_selectors(base_url); + initSelectors(base_url); renderTableAndChart(base_url + "/api/1.0/stats/companies", null, null, "company_chart", null); }); diff --git a/dashboard/vault.py b/dashboard/vault.py index 4bdb986a2..e8732dbd4 100644 --- a/dashboard/vault.py +++ b/dashboard/vault.py @@ -118,21 +118,7 @@ def _init_project_types(vault): runtime_storage_inst = vault['runtime_storage'] project_types = runtime_storage_inst.get_by_key('project_types') or {} - result = [] - parent = None - for pt in project_types: - is_child = pt.get('child', False) - if parent and is_child: - item = {'id': pt['id'], 'text': pt['title']} - if 'items' in parent: - parent['items'].append(item) - else: - parent['items'] = [item] - else: - parent = pt - result.append(parent) - - vault['project_types'] = result + vault['project_types'] = project_types vault['project_types_index'] = dict([(pt['id'], pt) for pt in project_types]) diff --git a/dashboard/web.py b/dashboard/web.py index 42ce3655e..2991df015 100644 --- a/dashboard/web.py +++ b/dashboard/web.py @@ -275,12 +275,14 @@ def get_contribution_json(records, **kwargs): @decorators.exception_handler() @decorators.response() @decorators.cached(ignore=['company']) -@decorators.jsonify('companies') +@decorators.jsonify() @decorators.record_filter(ignore=['company']) def get_companies_json(record_ids, **kwargs): memory_storage = vault.get_memory_storage() companies = memory_storage.get_index_keys_by_record_ids( 'company_name', record_ids) + if kwargs['_params']['company']: + companies.add(kwargs['_params']['company'][0]) result = [memory_storage.get_original_company_name(company) for company in companies] @@ -293,7 +295,7 @@ def get_companies_json(record_ids, **kwargs): @decorators.exception_handler() @decorators.response() @decorators.cached(ignore=['module']) -@decorators.jsonify('modules') +@decorators.jsonify() @decorators.record_filter(ignore=['module']) def get_modules_json(record_ids, **kwargs): module_id_index = vault.get_vault()['module_id_index'] @@ -313,7 +315,8 @@ def get_modules_json(record_ids, **kwargs): # keep only modules with specified tags if tags: module_ids = set(module_id for module_id in module_ids - if module_id_index[module_id].get('tag') in tags) + if ((module_id in module_id_index) and + (module_id_index[module_id].get('tag') in tags))) result = [] for module_id in module_ids: @@ -327,8 +330,9 @@ def get_modules_json(record_ids, **kwargs): @app.route('/api/1.0/companies/') @decorators.response() +@decorators.cached() @decorators.jsonify('company') -def get_company(company_name): +def get_company(company_name, **kwargs): memory_storage_inst = vault.get_memory_storage() for company in memory_storage_inst.get_companies(): if company.lower() == company_name.lower(): @@ -342,8 +346,9 @@ def get_company(company_name): @app.route('/api/1.0/modules/') @decorators.response() +@decorators.cached() @decorators.jsonify('module') -def get_module(module): +def get_module(module, **kwargs): module_id_index = vault.get_vault()['module_id_index'] module = module.lower() if module in module_id_index: @@ -410,11 +415,13 @@ def get_bpd(records, **kwargs): @decorators.exception_handler() @decorators.response() @decorators.cached(ignore=['user_id']) -@decorators.jsonify('users') +@decorators.jsonify() @decorators.record_filter(ignore=['user_id']) def get_users_json(record_ids, **kwargs): user_ids = vault.get_memory_storage().get_index_keys_by_record_ids( 'user_id', record_ids) + if kwargs['_params']['user_id']: + user_ids.add(kwargs['_params']['user_id'][0]) result = [{'id': user_id, 'text': (vault.get_user_from_runtime_storage(user_id) @@ -440,64 +447,35 @@ def get_user(user_id): @decorators.exception_handler() @decorators.response() @decorators.cached(ignore=parameters.FILTER_PARAMETERS) -@decorators.jsonify('releases') +@decorators.jsonify(root=('data', 'default')) def get_releases_json(**kwargs): - return [{'id': r['release_name'], 'text': r['release_name'].capitalize()} - for r in vault.get_release_options()] - - -@app.route('/api/1.0/releases/') -@decorators.response() -@decorators.jsonify('release') -def get_release_json(release): - if release != 'all': - if release not in vault.get_vault()['releases']: - release = parameters.get_default('release') - - return {'id': release, 'text': release.capitalize()} + return ([{'id': r['release_name'], 'text': r['release_name'].capitalize()} + for r in vault.get_release_options()], + parameters.get_default('release')) @app.route('/api/1.0/metrics') @decorators.exception_handler() @decorators.response() @decorators.cached(ignore=parameters.FILTER_PARAMETERS) -@decorators.jsonify('metrics') +@decorators.jsonify(root=('data', 'default')) def get_metrics_json(**kwargs): - return sorted([{'id': m, 'text': t} - for m, t in six.iteritems(parameters.METRIC_LABELS)], - key=operator.itemgetter('text')) - - -@app.route('/api/1.0/metrics/') -@decorators.response() -@decorators.jsonify('metric') -@decorators.exception_handler() -def get_metric_json(metric): - if metric not in parameters.METRIC_LABELS: - metric = parameters.get_default('metric') - return {'id': metric, 'text': parameters.METRIC_LABELS[metric]} + return (sorted([{'id': m, 'text': t} for m, t in + six.iteritems(parameters.METRIC_LABELS)], + key=operator.itemgetter('text')), + parameters.get_default('metric')) @app.route('/api/1.0/project_types') @decorators.response() @decorators.exception_handler() @decorators.cached(ignore=parameters.FILTER_PARAMETERS) -@decorators.jsonify('project_types') +@decorators.jsonify(root=('data', 'default')) def get_project_types_json(**kwargs): - return [{'id': pt['id'], 'text': pt['title'], 'items': pt.get('items', [])} - for pt in vault.get_project_types()] - - -@app.route('/api/1.0/project_types/') -@decorators.response() -@decorators.jsonify('project_type') -@decorators.exception_handler() -def get_project_type_json(project_type): - if not vault.is_project_type_valid(project_type): - project_type = parameters.get_default('project_type') - - pt = vault.get_project_type(project_type) - return {'id': pt['id'], 'text': pt['title']} + return ([{'id': pt['id'], 'text': pt['title'], + 'child': pt.get('child', False)} + for pt in vault.get_project_types()], + parameters.get_default('project_type')) def _get_week(kwargs, param_name): diff --git a/tests/api/test_companies.py b/tests/api/test_companies.py index 79b5ee205..b359434e9 100644 --- a/tests/api/test_companies.py +++ b/tests/api/test_companies.py @@ -59,14 +59,14 @@ class TestAPICompanies(test_api.TestAPI): response = self.app.get('/api/1.0/companies?metric=commits&' 'module=glance') - companies = json.loads(response.data)['companies'] + companies = json.loads(response.data)['data'] self.assertEqual([{'id': 'ibm', 'text': 'IBM'}, {'id': 'nec', 'text': 'NEC'}, {'id': 'ntt', 'text': 'NTT'}], companies) response = self.app.get('/api/1.0/companies?metric=marks&' 'module=glance') - companies = json.loads(response.data)['companies'] + companies = json.loads(response.data)['data'] self.assertEqual([{'id': 'ibm', 'text': 'IBM'}, {'id': 'nec', 'text': 'NEC'}], companies) diff --git a/tests/api/test_modules.py b/tests/api/test_modules.py index f832b55a3..906ae6a05 100644 --- a/tests/api/test_modules.py +++ b/tests/api/test_modules.py @@ -45,7 +45,7 @@ class TestAPIModules(test_api.TestAPI): response = self.app.get('/api/1.0/modules?' 'project_type=all&metric=commits') - modules = json.loads(response.data)['modules'] + modules = json.loads(response.data)['data'] self.assertEqual( [{'id': 'glance', 'text': 'glance', 'tag': 'module'}, {'id': 'nova', 'text': 'nova', 'tag': 'module'}, @@ -58,7 +58,7 @@ class TestAPIModules(test_api.TestAPI): response = self.app.get('/api/1.0/modules?module=nova-group&' 'project_type=integrated&metric=commits') - modules = json.loads(response.data)['modules'] + modules = json.loads(response.data)['data'] self.assertEqual( [{'id': 'glance', 'text': 'glance', 'tag': 'module'}, {'id': 'nova', 'text': 'nova', 'tag': 'module'}, diff --git a/tests/api/test_releases.py b/tests/api/test_releases.py index a4d76a48d..d3c303a94 100644 --- a/tests/api/test_releases.py +++ b/tests/api/test_releases.py @@ -28,17 +28,7 @@ class TestAPIReleases(test_api.TestAPI): {'release_name': 'icehouse', 'end_date': 1397692800}]}, test_api.make_records(record_type=['commit'])): response = self.app.get('/api/1.0/releases') - releases = json.loads(response.data)['releases'] + releases = json.loads(response.data)['data'] self.assertEqual(3, len(releases)) self.assertIn({'id': 'all', 'text': 'All'}, releases) self.assertIn({'id': 'icehouse', 'text': 'Icehouse'}, releases) - - def test_release_details(self): - with test_api.make_runtime_storage( - {'releases': [ - {'release_name': 'prehistory', 'end_date': 1365033600}, - {'release_name': 'icehouse', 'end_date': 1397692800}]}, - test_api.make_records(record_type=['commit'])): - response = self.app.get('/api/1.0/releases/icehouse') - release = json.loads(response.data)['release'] - self.assertEqual({'id': 'icehouse', 'text': 'Icehouse'}, release) diff --git a/tests/api/test_users.py b/tests/api/test_users.py index ca135b723..3adc9b51f 100644 --- a/tests/api/test_users.py +++ b/tests/api/test_users.py @@ -36,7 +36,7 @@ class TestAPIUsers(test_api.TestAPI): user_id=['john_doe', 'bill_smith'])): response = self.app.get('/api/1.0/users?' 'module=nova&metric=commits') - users = json.loads(response.data)['users'] + users = json.loads(response.data)['data'] self.assertEqual(2, len(users)) self.assertIn({'id': 'john_doe', 'text': 'John Doe'}, users) self.assertIn({'id': 'bill_smith', 'text': 'Bill Smith'}, users)