dataviz: refactor building of choice list (#71885)
This commit is contained in:
parent
af473d684e
commit
e8bd91b44e
|
@ -14,8 +14,9 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import dataclasses
|
||||
import datetime
|
||||
from collections import OrderedDict
|
||||
from collections import OrderedDict, defaultdict
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
|
@ -33,6 +34,21 @@ from .fields import StaticField
|
|||
from .models import ChartCell, ChartFiltersCell, ChartNgCell
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Choice:
|
||||
id: str
|
||||
label: str
|
||||
group: str = None
|
||||
|
||||
@staticmethod
|
||||
def get_field_choices(choices):
|
||||
choices_by_group = defaultdict(list)
|
||||
for choice in choices:
|
||||
choices_by_group[choice.group].append((choice.id, choice.label))
|
||||
|
||||
return list(choices_by_group.items())
|
||||
|
||||
|
||||
class ChartForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ChartCell
|
||||
|
@ -60,10 +76,10 @@ def trigger_statistics_list_refresh():
|
|||
|
||||
class ChartFiltersMixin:
|
||||
time_intervals = (
|
||||
('week', _('Week')),
|
||||
('month', _('Month')),
|
||||
('year', _('Year')),
|
||||
('weekday', _('Week day')),
|
||||
Choice('week', _('Week')),
|
||||
Choice('month', _('Month')),
|
||||
Choice('year', _('Year')),
|
||||
Choice('weekday', _('Week day')),
|
||||
)
|
||||
|
||||
def get_filter_fields(self, cell):
|
||||
|
@ -95,16 +111,15 @@ class ChartFiltersMixin:
|
|||
def build_choice_field(self, cell, filter_, initial):
|
||||
filter_id = filter_['id']
|
||||
|
||||
has_option_groups = isinstance(filter_['options'][0], list)
|
||||
if filter_['options'] and has_option_groups:
|
||||
choices = {
|
||||
group: [(opt['id'], opt['label']) for opt in options] for group, options in filter_['options']
|
||||
}
|
||||
choices_to_complete = choices[None] = choices.get(None, [])
|
||||
choices = list(choices.items())
|
||||
else:
|
||||
choices = [(option['id'], option['label']) for option in filter_['options']]
|
||||
choices_to_complete = choices
|
||||
filter_options = filter_['options']
|
||||
if not isinstance(filter_options[0], list):
|
||||
# no option groups, add empty one for consistency
|
||||
filter_options = [(None, filter_options)]
|
||||
choices = [
|
||||
Choice(id=opt['id'], label=opt['label'], group=group)
|
||||
for group, options in filter_options
|
||||
for opt in options
|
||||
]
|
||||
|
||||
if filter_id == 'time_interval':
|
||||
self.extend_time_interval_choices(choices)
|
||||
|
@ -112,37 +127,39 @@ class ChartFiltersMixin:
|
|||
required = filter_.get('required', False)
|
||||
multiple = filter_.get('multiple')
|
||||
if not required:
|
||||
choices_to_complete.insert(0, BLANK_CHOICE_DASH[0])
|
||||
choices.insert(0, Choice(*BLANK_CHOICE_DASH[0]))
|
||||
|
||||
extra_variables = cell.page.get_extra_variables_keys()
|
||||
variable_choices = [('variable:' + key, key) for key in extra_variables]
|
||||
variable_choices = [
|
||||
Choice(id='variable:' + key, label=key, group=_('Page variables')) for key in extra_variables
|
||||
]
|
||||
|
||||
if has_option_groups:
|
||||
possible_choices = {choice[0] for _, group_choices in choices for choice in group_choices}
|
||||
else:
|
||||
possible_choices = {choice[0] for choice in choices}
|
||||
for choice in initial if isinstance(initial, list) else [initial]:
|
||||
if not choice:
|
||||
continue
|
||||
if choice.startswith('variable:'):
|
||||
variable = choice.replace('variable:', '')
|
||||
if not variable in extra_variables:
|
||||
variable_choices.append((choice, _('%s (unavailable)') % variable))
|
||||
elif choice not in possible_choices:
|
||||
choices_to_complete.append((choice, _('%s (unavailable)') % choice))
|
||||
variable_choices.append(
|
||||
Choice(id=choice, label=_('%s (unavailable)') % variable, group=_('Page variables'))
|
||||
)
|
||||
elif not any(x.id == choice for x in choices):
|
||||
choices.append(Choice(id=choice, label=_('%s (unavailable)') % choice))
|
||||
|
||||
if variable_choices and not multiple and filter_id != 'time_interval':
|
||||
choices.append((_('Page variables'), variable_choices))
|
||||
choices.extend(variable_choices)
|
||||
|
||||
field_class = forms.MultipleChoiceField if multiple else forms.ChoiceField
|
||||
widget_class = MultiSelectWidget if multiple else forms.Select
|
||||
return field_class(
|
||||
field = field_class(
|
||||
label=filter_['label'],
|
||||
choices=choices,
|
||||
choices=Choice.get_field_choices(choices),
|
||||
required=required,
|
||||
initial=initial,
|
||||
widget=widget_class,
|
||||
)
|
||||
field.dataviz_choices = choices
|
||||
return field
|
||||
|
||||
def build_boolean_field(self, cell, filter_, initial):
|
||||
return forms.BooleanField(
|
||||
|
@ -152,10 +169,9 @@ class ChartFiltersMixin:
|
|||
)
|
||||
|
||||
def extend_time_interval_choices(self, choices):
|
||||
choice_ids = {choice_id for choice_id, _ in choices}
|
||||
if 'day' in choice_ids:
|
||||
if any(choice.id == 'day' for choice in choices):
|
||||
for choice in self.time_intervals:
|
||||
if choice[0] not in choice_ids:
|
||||
if choice not in choices:
|
||||
choices.append(choice)
|
||||
|
||||
def update_time_range_choices(self, statistic, exclude_template_choice=False):
|
||||
|
@ -399,21 +415,12 @@ class ChartFiltersForm(ChartFiltersMixin, forms.ModelForm):
|
|||
if field_name not in dynamic_fields or isinstance(field, forms.BooleanField):
|
||||
continue
|
||||
|
||||
has_option_groups = isinstance(dynamic_fields[field_name].choices[0][1], list)
|
||||
if has_option_groups and isinstance(field.choices[0][1], list):
|
||||
new_choices = []
|
||||
field_choices = {group_label: choices for group_label, choices in field.choices}
|
||||
for group_label, choices in dynamic_fields[field_name].choices:
|
||||
if group_label not in field_choices:
|
||||
continue
|
||||
new_choices.append(
|
||||
(group_label, [x for x in choices if x in field_choices[group_label]])
|
||||
)
|
||||
dynamic_fields[field_name].choices = new_choices
|
||||
else:
|
||||
dynamic_fields[field_name].choices = [
|
||||
x for x in dynamic_fields[field_name].choices if x in field.choices
|
||||
]
|
||||
dynamic_fields[field_name].dataviz_choices = [
|
||||
x for x in dynamic_fields[field_name].dataviz_choices if x in field.dataviz_choices
|
||||
]
|
||||
dynamic_fields[field_name].choices = Choice.get_field_choices(
|
||||
dynamic_fields[field_name].dataviz_choices
|
||||
)
|
||||
|
||||
if dynamic_fields[field_name].choices == []:
|
||||
del dynamic_fields[field_name]
|
||||
|
|
Loading…
Reference in New Issue