From 0d010f601cecacac01c26be572ae0d6444df9669 Mon Sep 17 00:00:00 2001 From: Sam Betts Date: Mon, 30 Mar 2015 16:49:24 +0100 Subject: [PATCH] Fix date pickers in metering modal The metering forms were using the date picker functionality from the d3 line chart library, this used to work when it was loaded as a whole page as the d3 libary would run intending to setup any d3 graphs however now it is being loaded as a modal the elements that would be affected by the d3 code do not exist at page load time. In order to get the date picker events to be added to the elements on the form when the modal loads, the JS in the forms template has been extended in this patch to support adding those events. This patch also changes the data attributes on the form elements so that they do not conflict with any d3 line chart elements. Alongside the javascript this patch fixes bug to do with parsing the dates in metering utils and adds UTs to prevent regression. Change-Id: I4e239daa03b2f54e434254bac48ba0cceb037b5d Closes-Bug: 1427756 --- .../static/horizon/js/horizon.d3linechart.js | 9 ++---- .../static/horizon/js/horizon.datepickers.js | 13 ++++++++ horizon/static/horizon/js/horizon.metering.js | 32 +++++++++++++++++++ horizon/templates/horizon/_scripts.html | 2 ++ .../dashboards/admin/metering/forms.py | 6 ++-- .../metering/templates/metering/_daily.html | 25 ++------------- .../metering/templates/metering/stats.html | 28 ++-------------- .../static/dashboard/scss/horizon.scss | 5 +++ openstack_dashboard/test/tests/utils.py | 25 +++++++++++++++ openstack_dashboard/utils/metering.py | 4 +-- 10 files changed, 88 insertions(+), 61 deletions(-) create mode 100644 horizon/static/horizon/js/horizon.datepickers.js create mode 100644 horizon/static/horizon/js/horizon.metering.js diff --git a/horizon/static/horizon/js/horizon.d3linechart.js b/horizon/static/horizon/js/horizon.d3linechart.js index 1457d33308..4250687332 100644 --- a/horizon/static/horizon/js/horizon.d3linechart.js +++ b/horizon/static/horizon/js/horizon.d3linechart.js @@ -757,13 +757,8 @@ horizon.d3_line_chart = { * connected to charts. */ var bind_datepicker_change = function(settings) { - - $(datepicker_selector).each(function() { - var el = $(this); - el.datepicker({format: 'yyyy-mm-dd', - setDate: new Date(), - showButtonPanel: true}); - }); + var now = new Date(); + horizon.datepickers.add(datepicker_selector); delegate_event_and_refresh_charts(datepicker_selector, 'changeDate', settings); }; diff --git a/horizon/static/horizon/js/horizon.datepickers.js b/horizon/static/horizon/js/horizon.datepickers.js new file mode 100644 index 0000000000..a7563fcf6f --- /dev/null +++ b/horizon/static/horizon/js/horizon.datepickers.js @@ -0,0 +1,13 @@ +horizon.datepickers = { + add: function(selector) { + $(selector).each(function () { + var el = $(this); + el.datepicker({ + format: 'yyyy-mm-dd', + setDate: new Date(), + showButtonPanel: true, + language: horizon.datepickerLocale + }); + }); + } +}; diff --git a/horizon/static/horizon/js/horizon.metering.js b/horizon/static/horizon/js/horizon.metering.js new file mode 100644 index 0000000000..c4c9a4d412 --- /dev/null +++ b/horizon/static/horizon/js/horizon.metering.js @@ -0,0 +1,32 @@ +horizon.metering = { + init_create_usage_report_form: function() { + horizon.datepickers.add('input[data-date-picker="True"]'); + horizon.metering.add_change_event_to_period_dropdown(); + horizon.metering.show_or_hide_date_fields(); + }, + init_stats_page: function() { + if (typeof horizon.d3_line_chart !== 'undefined') { + horizon.d3_line_chart.init("div[data-chart-type='line_chart']", + {'auto_resize': true}); + } + horizon.metering.add_change_event_to_period_dropdown(); + horizon.metering.show_or_hide_date_fields(); + }, + show_or_hide_date_fields: function() { + $("#date_from .controls input, #date_to .controls input").val(''); + if ($("#id_period").find("option:selected").val() === "other"){ + $("#id_date_from, #id_date_to").parent().parent().show(); + return true; + } else { + $("#id_date_from, #id_date_to").parent().parent().hide(); + return false; + } + }, + add_change_event_to_period_dropdown: function() { + $("#id_period").change(function(evt) { + if (horizon.metering.show_or_hide_date_fields()) { + evt.stopPropagation(); + } + }); + } +}; diff --git a/horizon/templates/horizon/_scripts.html b/horizon/templates/horizon/_scripts.html index d5052b821a..edaf72a9f6 100644 --- a/horizon/templates/horizon/_scripts.html +++ b/horizon/templates/horizon/_scripts.html @@ -76,6 +76,7 @@ + @@ -92,6 +93,7 @@ + diff --git a/openstack_dashboard/dashboards/admin/metering/forms.py b/openstack_dashboard/dashboards/admin/metering/forms.py index 31fe953cbe..d75ee028cf 100644 --- a/openstack_dashboard/dashboards/admin/metering/forms.py +++ b/openstack_dashboard/dashboards/admin/metering/forms.py @@ -34,12 +34,10 @@ class UsageReportForm(forms.SelfHandlingForm): choices=PERIOD_CHOICES) date_from = forms.DateField(label=_("From"), required=False, widget=forms.TextInput( - attrs={'data-line-chart-command': - 'date_picker_change'})) + attrs={'data-date-picker': True})) date_to = forms.DateField(label=_("To"), required=False, widget=forms.TextInput( - attrs={'data-line-chart-command': - 'date_picker_change'})) + attrs={'data-date-picker': True})) def clean_date_from(self): period = self.cleaned_data['period'] diff --git a/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html b/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html index a19572c049..fbdcb315e9 100644 --- a/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html +++ b/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html @@ -27,31 +27,12 @@ {% block modal-js %} {% endblock %} diff --git a/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html b/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html index cf17a33ff3..47eea47b77 100644 --- a/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html +++ b/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html @@ -166,35 +166,11 @@ diff --git a/openstack_dashboard/static/dashboard/scss/horizon.scss b/openstack_dashboard/static/dashboard/scss/horizon.scss index d8328eab47..02d0fc2da3 100644 --- a/openstack_dashboard/static/dashboard/scss/horizon.scss +++ b/openstack_dashboard/static/dashboard/scss/horizon.scss @@ -618,6 +618,11 @@ td.loading { /* Forms */ + +.datepicker { + z-index: $zindex-popover !important; +} + .datepicker input{ @extend .form-control; } diff --git a/openstack_dashboard/test/tests/utils.py b/openstack_dashboard/test/tests/utils.py index 6581ecc940..5ab2cd6b60 100644 --- a/openstack_dashboard/test/tests/utils.py +++ b/openstack_dashboard/test/tests/utils.py @@ -13,10 +13,12 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime import uuid from openstack_dashboard.test import helpers as test from openstack_dashboard.utils import filters +from openstack_dashboard.utils import metering class UtilsFilterTests(test.TestCase): @@ -38,3 +40,26 @@ class UtilsFilterTests(test.TestCase): def test_reject_random_string(self): val = '55WbJTpJDf' self.assertRaises(ValueError, filters.get_int_or_uuid, val) + + +class UtilsMeteringTests(test.TestCase): + + def test_calc_date_args_strings(self): + date_from, date_to = metering.calc_date_args( + "2012-04-11", "2012-04-12", "other") + self.assertTrue(type(date_from) is datetime.datetime) + self.assertTrue(type(date_to) is datetime.datetime) + self.assertEqual(str(date_from.tzinfo), "UTC") + self.assertEqual(str(date_to.tzinfo), "UTC") + + def test_calc_date_args_datetime_dates(self): + date_from, date_to = metering.calc_date_args( + datetime.date(2012, 4, 11), datetime.date(2012, 4, 12), "other") + self.assertTrue(type(date_from) is datetime.datetime) + self.assertTrue(type(date_to) is datetime.datetime) + self.assertEqual(str(date_from.tzinfo), "UTC") + self.assertEqual(str(date_to.tzinfo), "UTC") + + def test_calc_date_args_invalid(self): + self.assertRaises( + ValueError, metering.calc_date_args, object, object, "other") diff --git a/openstack_dashboard/utils/metering.py b/openstack_dashboard/utils/metering.py index 9cd42fe61a..b6eb50f566 100644 --- a/openstack_dashboard/utils/metering.py +++ b/openstack_dashboard/utils/metering.py @@ -61,7 +61,7 @@ def calc_date_args(date_from, date_to, date_options): try: if date_from: date_from = pytz.utc.localize( - datetime.datetime.strptime(date_from, "%Y-%m-%d")) + datetime.datetime.strptime(str(date_from), "%Y-%m-%d")) else: # TODO(lsmola) there should be probably the date # of the first sample as default, so it correctly @@ -70,7 +70,7 @@ def calc_date_args(date_from, date_to, date_options): pass if date_to: date_to = pytz.utc.localize( - datetime.datetime.strptime(date_to, "%Y-%m-%d")) + datetime.datetime.strptime(str(date_to), "%Y-%m-%d")) # It returns the beginning of the day, I want the end of # the day, so I add one day without a second. date_to = (date_to + datetime.timedelta(days=1) -