dataviz: hide future time range choices by default (#62862)

This commit is contained in:
Valentin Deniaud 2022-03-16 16:08:29 +01:00
parent 6f040993b2
commit 73e345a89d
6 changed files with 161 additions and 24 deletions

View File

@ -27,7 +27,7 @@ from django.utils.translation import ugettext_lazy as _
from combo.utils import cache_during_request, requests, spooler
from .models import TIME_FILTERS, ChartCell, ChartNgCell
from .models import ChartCell, ChartNgCell
class ChartForm(forms.ModelForm):
@ -110,6 +110,17 @@ class ChartFiltersMixin:
if choice[0] not in choice_ids:
choices.append(choice)
def update_time_range_choices(self, statistic, exclude_template_choice=False):
choices = self.fields['time_range'].choices
if not statistic.has_future_data:
choices = [choice for choice in choices if not choice[0].startswith('next')]
if exclude_template_choice:
choices = [choice for choice in choices if choice[0] != 'range-template']
self.fields['time_range'].choices = choices
class ChartNgForm(ChartFiltersMixin, forms.ModelForm):
class Meta:
@ -136,16 +147,6 @@ class ChartNgForm(ChartFiltersMixin, forms.ModelForm):
trigger_statistics_list_refresh()
super().__init__(*args, **kwargs)
if not self.instance.statistic or self.instance.statistic.service_slug == 'bijoe':
for field in (
'time_range',
'time_range_start',
'time_range_end',
'time_range_start_template',
'time_range_end_template',
):
del self.fields[field]
stat_field = self.fields['statistic']
if not self.instance.statistic:
stat_field.queryset = stat_field.queryset.filter(available=True)
@ -155,6 +156,17 @@ class ChartNgForm(ChartFiltersMixin, forms.ModelForm):
Q(available=True) | Q(pk=self.instance.statistic.pk)
)
self.add_filter_fields()
self.update_time_range_choices(self.instance.statistic)
if not self.instance.statistic or self.instance.statistic.service_slug == 'bijoe':
for field in (
'time_range',
'time_range_start',
'time_range_end',
'time_range_start_template',
'time_range_end_template',
):
del self.fields[field]
def add_filter_fields(self):
new_fields = OrderedDict()
@ -248,7 +260,6 @@ class ChartFiltersForm(ChartFiltersMixin, forms.ModelForm):
def __init__(self, *args, **kwargs):
page = kwargs.pop('page')
super().__init__(*args, **kwargs)
self.fields['time_range'].choices = BLANK_CHOICE_DASH + TIME_FILTERS
chart_cells = list(ChartNgCell.objects.filter(page=page, statistic__isnull=False).order_by('order'))
if not chart_cells:
@ -260,6 +271,7 @@ class ChartFiltersForm(ChartFiltersMixin, forms.ModelForm):
self.fields[field].initial = getattr(first_cell, field)
dynamic_fields = self.get_filter_fields(first_cell)
dynamic_fields_values = {k: v for k, v in first_cell.filter_params.items()}
self.update_time_range_choices(first_cell.statistic, exclude_template_choice=True)
for cell in chart_cells[1:]:
cell_filter_fields = self.get_filter_fields(cell)
@ -285,4 +297,7 @@ class ChartFiltersForm(ChartFiltersMixin, forms.ModelForm):
if dynamic_fields[field_name].choices == []:
del dynamic_fields[field_name]
if 'time_range' in self.fields:
self.update_time_range_choices(cell.statistic)
self.fields.update(dynamic_fields)

View File

@ -2,7 +2,7 @@
from django.db import migrations, models
from combo.apps.dataviz.models import TIME_FILTERS, TIME_FILTERS_TEMPLATE
from combo.apps.dataviz.models import TIME_FILTERS
class Migration(migrations.Migration):
@ -17,7 +17,7 @@ class Migration(migrations.Migration):
name='time_range',
field=models.CharField(
blank=True,
choices=TIME_FILTERS + TIME_FILTERS_TEMPLATE,
choices=TIME_FILTERS,
max_length=20,
verbose_name='Shown period',
),

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.19 on 2022-03-17 10:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dataviz', '0022_chartngcell_subfilters'),
]
operations = [
migrations.AddField(
model_name='statistic',
name='has_future_data',
field=models.BooleanField(default=False),
),
]

View File

@ -139,6 +139,7 @@ class Statistic(models.Model):
site_title = models.CharField(_('Site title'), max_length=256)
url = models.URLField(_('Data URL'))
filters = JSONField(default=list)
has_future_data = models.BooleanField(default=False)
available = models.BooleanField(_('Available data'), default=True)
last_update = models.DateTimeField(_('Last update'), null=True, auto_now=True)
@ -178,8 +179,8 @@ TIME_FILTERS = [
('current-week', _('Current week')),
('next-week', _('Next week')),
('range', _('Free range (date)')),
('range-template', _('Free range (template)')),
]
TIME_FILTERS_TEMPLATE = [('range-template', _('Free range (template)'))]
@register_cell_class
@ -202,7 +203,7 @@ class ChartNgCell(CellBase):
_('Shown period'),
max_length=20,
blank=True,
choices=TIME_FILTERS + TIME_FILTERS_TEMPLATE,
choices=TIME_FILTERS,
)
time_range_start = models.DateField(_('From'), null=True, blank=True)
time_range_end = models.DateField(_('To'), null=True, blank=True)

View File

@ -45,11 +45,12 @@ def update_available_statistics():
url=stat.get('data-url') or stat['url'],
site_title=site_dict.get('title', ''),
filters=stat.get('filters', []),
has_future_data=stat.get('future_data', False),
available=True,
)
)
update_fields = ('label', 'url', 'site_title', 'filters', 'available')
update_fields = ('label', 'url', 'site_title', 'filters', 'available', 'has_future_data')
all_statistics = {stat.natural_key(): stat for stat in Statistic.objects.all()}
statistics_to_create = []
statistics_to_update = {}

View File

@ -433,6 +433,12 @@ STATISTICS_LIST = {
},
],
},
{
'url': 'https://authentic.example.com/api/statistics/future-data/',
'name': 'With future data',
'id': 'with-future-data',
'future_data': True,
},
]
}
@ -521,6 +527,14 @@ def new_api_mock(url, request):
if 'form=error' in url.query:
return {'content': b'', 'request': request, 'status_code': 404}
return {'content': json.dumps(response), 'request': request, 'status_code': 200}
if url.path == '/api/statistics/future-data/':
response = {
'data': {
'series': [{'data': [None, 16, 2], 'label': 'Serie 1'}],
'x_labels': ['2020-10', '2020-11', '2020-12'],
},
}
return {'content': json.dumps(response), 'request': request, 'status_code': 200}
@pytest.fixture
@ -1368,6 +1382,51 @@ def test_chartng_cell_manager_new_api(app, admin_user, new_api_statistics):
assert cell.get_filter_params() == {}
@with_httmock(new_api_mock)
def test_chartng_cell_manager_future_data(app, admin_user, new_api_statistics):
page = Page.objects.create(title='One', slug='index')
cell = ChartNgCell(page=page, order=1, placeholder='content')
cell.statistic = Statistic.objects.get(slug='one-serie')
cell.save()
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
field_prefix = 'cdataviz_chartngcell-%s-' % cell.id
time_range_field = resp.form[field_prefix + 'time_range']
assert time_range_field.value == ''
assert time_range_field.options == [
('', True, '---------'),
('previous-year', False, 'Previous year'),
('current-year', False, 'Current year'),
('previous-month', False, 'Previous month'),
('current-month', False, 'Current month'),
('previous-week', False, 'Previous week'),
('current-week', False, 'Current week'),
('range', False, 'Free range (date)'),
('range-template', False, 'Free range (template)'),
]
stat_with_future_data = Statistic.objects.get(slug='with-future-data')
resp.form[field_prefix + 'statistic'] = stat_with_future_data.pk
resp = resp.form.submit().follow()
time_range_field = resp.form[field_prefix + 'time_range']
assert time_range_field.value == ''
assert time_range_field.options == [
('', True, '---------'),
('previous-year', False, 'Previous year'),
('current-year', False, 'Current year'),
('next-year', False, 'Next year'),
('previous-month', False, 'Previous month'),
('current-month', False, 'Current month'),
('next-month', False, 'Next month'),
('previous-week', False, 'Previous week'),
('current-week', False, 'Current week'),
('next-week', False, 'Next week'),
('range', False, 'Free range (date)'),
('range-template', False, 'Free range (template)'),
]
@with_httmock(new_api_mock)
def test_chartng_cell_manager_subfilters(app, admin_user, new_api_statistics):
page = Page.objects.create(title='One', slug='index')
@ -2092,13 +2151,10 @@ def test_chart_filters_cell(new_api_statistics, app, admin_user, nocache):
('', True, '---------'),
('previous-year', False, 'Previous year'),
('current-year', False, 'Current year'),
('next-year', False, 'Next year'),
('previous-month', False, 'Previous month'),
('current-month', False, 'Current month'),
('next-month', False, 'Next month'),
('previous-week', False, 'Previous week'),
('current-week', False, 'Current week'),
('next-week', False, 'Next week'),
('range', False, 'Free range (date)'),
]
@ -2161,7 +2217,7 @@ def test_chart_filters_cell(new_api_statistics, app, admin_user, nocache):
assert resp.form[field].options == old_resp.form[field].options
# changing time_interval value makes interval fields disappear
cell.time_range = 'next-year'
cell.time_range = 'previous-year'
cell.save()
old_resp = resp
resp = app.get('/')
@ -2171,10 +2227,10 @@ def test_chart_filters_cell(new_api_statistics, app, admin_user, nocache):
assert resp.form['time_interval'].options == old_resp.form['time_interval'].options
# setting the same value for the other cell makes it appear again
first_cell.time_range = 'next-year'
first_cell.time_range = 'previous-year'
first_cell.save()
resp = app.get('/')
assert resp.form['time_range'].value == 'next-year'
assert resp.form['time_range'].value == 'previous-year'
assert resp.form['time_interval'].options == old_resp.form['time_interval'].options
# only common choices are shown
@ -2191,7 +2247,7 @@ def test_chart_filters_cell(new_api_statistics, app, admin_user, nocache):
first_cell.statistic.save()
resp = app.get('/')
assert 'time_interval' not in resp.form.fields
assert resp.form['time_range'].value == 'next-year'
assert resp.form['time_range'].value == 'previous-year'
# form is not shown if no common filters exist
first_cell.time_range = 'current-year'
@ -2200,6 +2256,52 @@ def test_chart_filters_cell(new_api_statistics, app, admin_user, nocache):
assert 'No filters are available' in resp.text
@with_httmock(new_api_mock)
def test_chart_filters_cell_future_data(app, admin_user, new_api_statistics):
page = Page.objects.create(title='One', slug='index')
cell = ChartNgCell(page=page, order=1, placeholder='content')
cell.statistic = Statistic.objects.get(slug='with-future-data')
cell.save()
ChartFiltersCell.objects.create(page=page, order=2, placeholder='content')
app = login(app)
resp = app.get('/')
time_range_field = resp.form['time_range']
assert time_range_field.value == ''
assert time_range_field.options == [
('', True, '---------'),
('previous-year', False, 'Previous year'),
('current-year', False, 'Current year'),
('next-year', False, 'Next year'),
('previous-month', False, 'Previous month'),
('current-month', False, 'Current month'),
('next-month', False, 'Next month'),
('previous-week', False, 'Previous week'),
('current-week', False, 'Current week'),
('next-week', False, 'Next week'),
('range', False, 'Free range (date)'),
]
# adding cell without future data makes choice disappear
cell = ChartNgCell(page=page, order=3, placeholder='content')
cell.statistic = Statistic.objects.get(slug='one-serie')
cell.save()
resp = app.get('/')
time_range_field = resp.form['time_range']
assert time_range_field.value == ''
assert time_range_field.options == [
('', True, '---------'),
('previous-year', False, 'Previous year'),
('current-year', False, 'Current year'),
('previous-month', False, 'Previous month'),
('current-month', False, 'Current month'),
('previous-week', False, 'Previous week'),
('current-week', False, 'Current week'),
('range', False, 'Free range (date)'),
]
@with_httmock(new_api_mock)
def test_chart_filters_cell_with_subfilters(new_api_statistics, app, admin_user, nocache):
page = Page.objects.create(title='One', slug='index')