1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-14 09:08:32 +00:00

Sort by sort reference in grouped aggregate service

This commit is contained in:
Petr Stribny 2025-03-04 03:15:23 +00:00
parent d664710948
commit 1ba677a437
9 changed files with 470 additions and 196 deletions
enterprise
backend
src/baserow_enterprise
api/integrations/local_baserow
integrations/local_baserow
migrations
services
tests/baserow_enterprise_tests
web-frontend/modules/baserow_enterprise/dashboard/components/data_source

View file

@ -3,6 +3,7 @@ from rest_framework import serializers
from baserow_enterprise.integrations.local_baserow.models import ( from baserow_enterprise.integrations.local_baserow.models import (
LocalBaserowTableServiceAggregationGroupBy, LocalBaserowTableServiceAggregationGroupBy,
LocalBaserowTableServiceAggregationSeries, LocalBaserowTableServiceAggregationSeries,
LocalBaserowTableServiceAggregationSortBy,
) )
@ -22,3 +23,11 @@ class LocalBaserowTableServiceAggregationGroupBySerializer(serializers.ModelSeri
class Meta: class Meta:
model = LocalBaserowTableServiceAggregationGroupBy model = LocalBaserowTableServiceAggregationGroupBy
fields = ("order", "field_id") fields = ("order", "field_id")
class LocalBaserowTableServiceAggregationSortBySerializer(serializers.ModelSerializer):
order = serializers.IntegerField(read_only=True)
class Meta:
model = LocalBaserowTableServiceAggregationSortBy
fields = ("order", "sort_on", "reference", "direction")

View file

@ -118,3 +118,35 @@ class LocalBaserowTableServiceAggregationGroupBy(models.Model):
class Meta: class Meta:
ordering = ("order", "id") ordering = ("order", "id")
class SortOn(models.TextChoices):
SERIES = "SERIES", "Series"
GROUP_BY = "GROUP_BY", "Group by"
PRIMARY = "PRIMARY", "Primary"
class SortDirection(models.TextChoices):
ASCENDING = "ASC", "Ascending"
DESCENDING = "DESC", "Descending"
class LocalBaserowTableServiceAggregationSortBy(models.Model):
"""
A sort by for aggregations applicable to a `LocalBaserowTableService`
integration service.
"""
service = models.ForeignKey(
Service,
related_name="service_aggregation_sorts",
help_text="The service which this aggregation series belongs to.",
on_delete=models.CASCADE,
)
sort_on = models.CharField(max_length=255, choices=SortOn.choices)
reference = models.CharField(max_length=255)
direction = models.CharField(max_length=255, choices=SortDirection.choices)
order = models.PositiveIntegerField()
class Meta:
ordering = ("order", "id")

View file

@ -1,7 +1,5 @@
from typing import TYPE_CHECKING, Type
from django.conf import settings from django.conf import settings
from django.db.models import OrderBy, QuerySet from django.db.models import F
from rest_framework.exceptions import ValidationError as DRFValidationError from rest_framework.exceptions import ValidationError as DRFValidationError
@ -12,23 +10,20 @@ from baserow.contrib.integrations.local_baserow.integration_types import (
) )
from baserow.contrib.integrations.local_baserow.mixins import ( from baserow.contrib.integrations.local_baserow.mixins import (
LocalBaserowTableServiceFilterableMixin, LocalBaserowTableServiceFilterableMixin,
LocalBaserowTableServiceSortableMixin,
)
from baserow.contrib.integrations.local_baserow.models import (
LocalBaserowTableServiceSort,
Service,
) )
from baserow.contrib.integrations.local_baserow.models import Service
from baserow.contrib.integrations.local_baserow.service_types import ( from baserow.contrib.integrations.local_baserow.service_types import (
LocalBaserowViewServiceType, LocalBaserowViewServiceType,
) )
from baserow.core.services.dispatch_context import DispatchContext from baserow.core.services.dispatch_context import DispatchContext
from baserow.core.services.exceptions import ServiceImproperlyConfigured from baserow.core.services.exceptions import ServiceImproperlyConfigured
from baserow.core.services.registries import DispatchTypes from baserow.core.services.registries import DispatchTypes
from baserow.core.services.types import DispatchResult, ServiceSortDictSubClass from baserow.core.services.types import DispatchResult
from baserow.core.utils import atomic_if_not_already from baserow.core.utils import atomic_if_not_already
from baserow_enterprise.api.integrations.local_baserow.serializers import ( from baserow_enterprise.api.integrations.local_baserow.serializers import (
LocalBaserowTableServiceAggregationGroupBySerializer, LocalBaserowTableServiceAggregationGroupBySerializer,
LocalBaserowTableServiceAggregationSeriesSerializer, LocalBaserowTableServiceAggregationSeriesSerializer,
LocalBaserowTableServiceAggregationSortBySerializer,
) )
from baserow_enterprise.integrations.local_baserow.models import ( from baserow_enterprise.integrations.local_baserow.models import (
LocalBaserowGroupedAggregateRows, LocalBaserowGroupedAggregateRows,
@ -37,20 +32,18 @@ from baserow_enterprise.integrations.registries import grouped_aggregation_regis
from baserow_enterprise.services.types import ( from baserow_enterprise.services.types import (
ServiceAggregationGroupByDict, ServiceAggregationGroupByDict,
ServiceAggregationSeriesDict, ServiceAggregationSeriesDict,
ServiceAggregationSortByDict,
) )
from .models import ( from .models import (
LocalBaserowTableServiceAggregationGroupBy, LocalBaserowTableServiceAggregationGroupBy,
LocalBaserowTableServiceAggregationSeries, LocalBaserowTableServiceAggregationSeries,
LocalBaserowTableServiceAggregationSortBy,
) )
if TYPE_CHECKING:
from baserow.contrib.database.table.models import GeneratedTableModel
class LocalBaserowGroupedAggregateRowsUserServiceType( class LocalBaserowGroupedAggregateRowsUserServiceType(
LocalBaserowTableServiceFilterableMixin, LocalBaserowTableServiceFilterableMixin,
LocalBaserowTableServiceSortableMixin,
LocalBaserowViewServiceType, LocalBaserowViewServiceType,
): ):
""" """
@ -62,10 +55,7 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
type = "local_baserow_grouped_aggregate_rows" type = "local_baserow_grouped_aggregate_rows"
model_class = LocalBaserowGroupedAggregateRows model_class = LocalBaserowGroupedAggregateRows
dispatch_type = DispatchTypes.DISPATCH_DATA_SOURCE dispatch_type = DispatchTypes.DISPATCH_DATA_SOURCE
serializer_mixins = ( serializer_mixins = LocalBaserowTableServiceFilterableMixin.mixin_serializer_mixins
LocalBaserowTableServiceFilterableMixin.mixin_serializer_mixins
+ LocalBaserowTableServiceSortableMixin.mixin_serializer_mixins
)
def get_schema_name(self, service: LocalBaserowGroupedAggregateRows) -> str: def get_schema_name(self, service: LocalBaserowGroupedAggregateRows) -> str:
return f"GroupedAggregation{service.id}Schema" return f"GroupedAggregation{service.id}Schema"
@ -80,7 +70,9 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
super() super()
.enhance_queryset(queryset) .enhance_queryset(queryset)
.prefetch_related( .prefetch_related(
"service_aggregation_series", "service_aggregation_group_bys" "service_aggregation_series",
"service_aggregation_group_bys",
"service_aggregation_sorts",
) )
) )
@ -96,21 +88,22 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
return ( return (
super().serializer_field_names super().serializer_field_names
+ LocalBaserowTableServiceFilterableMixin.mixin_serializer_field_names + LocalBaserowTableServiceFilterableMixin.mixin_serializer_field_names
+ LocalBaserowTableServiceSortableMixin.mixin_serializer_field_names ) + ["aggregation_series", "aggregation_group_bys", "aggregation_sorts"]
) + ["aggregation_series", "aggregation_group_bys"]
@property @property
def serializer_field_overrides(self): def serializer_field_overrides(self):
return { return {
**super().serializer_field_overrides, **super().serializer_field_overrides,
**LocalBaserowTableServiceFilterableMixin.mixin_serializer_field_overrides, **LocalBaserowTableServiceFilterableMixin.mixin_serializer_field_overrides,
**LocalBaserowTableServiceSortableMixin.mixin_serializer_field_overrides,
"aggregation_series": LocalBaserowTableServiceAggregationSeriesSerializer( "aggregation_series": LocalBaserowTableServiceAggregationSeriesSerializer(
many=True, source="service_aggregation_series", required=False many=True, source="service_aggregation_series", required=False
), ),
"aggregation_group_bys": LocalBaserowTableServiceAggregationGroupBySerializer( "aggregation_group_bys": LocalBaserowTableServiceAggregationGroupBySerializer(
many=True, source="service_aggregation_group_bys", required=False many=True, source="service_aggregation_group_bys", required=False
), ),
"aggregation_sorts": LocalBaserowTableServiceAggregationSortBySerializer(
many=True, source="service_aggregation_sorts", required=False
),
} }
class SerializedDict( class SerializedDict(
@ -119,6 +112,7 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
): ):
service_aggregation_series: list[ServiceAggregationSeriesDict] service_aggregation_series: list[ServiceAggregationSeriesDict]
service_aggregation_group_bys: list[ServiceAggregationGroupByDict] service_aggregation_group_bys: list[ServiceAggregationGroupByDict]
service_aggregation_sorts: list[ServiceAggregationSortByDict]
def _update_service_aggregation_series( def _update_service_aggregation_series(
self, self,
@ -224,48 +218,43 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
] ]
) )
def _update_service_sortings( def _update_service_sorts(
self, self,
service: LocalBaserowGroupedAggregateRows, service: LocalBaserowGroupedAggregateRows,
service_sorts: list[ServiceSortDictSubClass] | None = None, service_sorts: list[ServiceAggregationSortByDict] | None = None,
): ):
with atomic_if_not_already(): with atomic_if_not_already():
service.service_sorts.all().delete() service.service_aggregation_sorts.all().delete()
if service_sorts is not None: if service_sorts is not None:
table_field_ids = service.table.field_set.values_list("id", flat=True)
model = service.table.get_model() model = service.table.get_model()
allowed_sort_field_ids = [ allowed_sort_references = [
series.field_id f"field_{series.field_id}_{series.aggregation_type}"
for series in service.service_aggregation_series.all() for series in service.service_aggregation_series.all()
if series.aggregation_type is not None
and series.field_id is not None
] ]
if service.service_aggregation_group_bys.count() > 0: if service.service_aggregation_group_bys.count() > 0:
group_by = service.service_aggregation_group_bys.all()[0] group_by = service.service_aggregation_group_bys.all()[0]
allowed_sort_field_ids += ( allowed_sort_references += (
[group_by.field_id] [f"field_{group_by.field_id}"]
if group_by.field_id is not None if group_by.field_id is not None
else [model.get_primary_field().id] else [f"field_{model.get_primary_field().id}"]
) )
def validate_sort(service_sort): def validate_sort(service_sort):
if service_sort["field"].id not in table_field_ids: if service_sort["reference"] not in allowed_sort_references:
raise DRFValidationError( raise DRFValidationError(
detail=f"The field with ID {service_sort['field'].id} is not " detail=f"The reference sort '{service_sort['reference']}' cannot be used for sorting.",
"related to the given table.", code="invalid",
code="invalid_field",
)
if service_sort["field"].id not in allowed_sort_field_ids:
raise DRFValidationError(
detail=f"The field with ID {service_sort['field'].id} cannot be used for sorting.",
code="invalid_field",
) )
return True return True
LocalBaserowTableServiceSort.objects.bulk_create( LocalBaserowTableServiceAggregationSortBy.objects.bulk_create(
[ [
LocalBaserowTableServiceSort( LocalBaserowTableServiceAggregationSortBy(
**service_sort, service=service, order=index **service_sort, service=service, order=index
) )
for index, service_sort in enumerate(service_sorts) for index, service_sort in enumerate(service_sorts)
@ -290,8 +279,10 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
self._update_service_aggregation_group_bys( self._update_service_aggregation_group_bys(
instance, values.pop("service_aggregation_group_bys") instance, values.pop("service_aggregation_group_bys")
) )
if "service_sorts" in values: if "service_aggregation_sorts" in values:
self._update_service_sortings(instance, values.pop("service_sorts")) self._update_service_sorts(
instance, values.pop("service_aggregation_sorts")
)
def after_update( def after_update(
self, self,
@ -328,10 +319,12 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
elif from_table and to_table: elif from_table and to_table:
instance.service_aggregation_group_bys.all().delete() instance.service_aggregation_group_bys.all().delete()
if "service_sorts" in values: if "service_aggregation_sorts" in values:
self._update_service_sortings(instance, values.pop("service_sorts")) self._update_service_sorts(
instance, values.pop("service_aggregation_sorts")
)
elif from_table and to_table: elif from_table and to_table:
instance.service_sorts.all().delete() instance.service_aggregation_sorts.all().delete()
def export_prepared_values(self, instance: Service) -> dict[str, any]: def export_prepared_values(self, instance: Service) -> dict[str, any]:
values = super().export_prepared_values(instance) values = super().export_prepared_values(instance)
@ -382,16 +375,6 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
**kwargs, **kwargs,
) )
def get_dispatch_sorts(
self,
service: LocalBaserowGroupedAggregateRows,
queryset: QuerySet,
model: Type["GeneratedTableModel"],
) -> tuple[list[OrderBy], QuerySet]:
service_sorts = service.service_sorts.all()
sort_ordering = [service_sort.get_order_by() for service_sort in service_sorts]
return sort_ordering, queryset
def dispatch_data( def dispatch_data(
self, self,
service: LocalBaserowGroupedAggregateRows, service: LocalBaserowGroupedAggregateRows,
@ -412,24 +395,6 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
model = self.get_table_model(service) model = self.get_table_model(service)
queryset = self.build_queryset(service, table, dispatch_context, model=model) queryset = self.build_queryset(service, table, dispatch_context, model=model)
allowed_sort_field_ids = [
series.field_id for series in service.service_aggregation_series.all()
]
if service.service_aggregation_group_bys.count() > 0:
group_by = service.service_aggregation_group_bys.all()[0]
allowed_sort_field_ids += (
[group_by.field_id]
if group_by.field_id is not None
else [model.get_primary_field().id]
)
for sort_by in service.service_sorts.all():
if sort_by.field_id not in allowed_sort_field_ids:
raise ServiceImproperlyConfigured(
f"The field with ID {sort_by.field.id} cannot be used for sorting."
)
group_by_values = [] group_by_values = []
for group_by in service.service_aggregation_group_bys.all(): for group_by in service.service_aggregation_group_bys.all():
if group_by.field is None: if group_by.field is None:
@ -482,6 +447,54 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
queryset = queryset.annotate(**value.annotations) queryset = queryset.annotate(**value.annotations)
combined_agg_dict[key] = value.aggregation combined_agg_dict[key] = value.aggregation
allowed_sort_references = [
f"field_{series.field_id}_{series.aggregation_type}"
for series in service.service_aggregation_series.all()
if series.aggregation_type is not None and series.field_id is not None
]
if service.service_aggregation_group_bys.count() > 0:
group_by = service.service_aggregation_group_bys.all()[0]
allowed_sort_references += (
[f"field_{group_by.field_id}"]
if group_by.field_id is not None
else [f"field_{model.get_primary_field().id}"]
)
sorts = []
sort_annotations = {}
for sort_by in service.service_aggregation_sorts.all():
if sort_by.reference not in allowed_sort_references:
raise ServiceImproperlyConfigured(
f"The sort reference '{sort_by.reference}' cannot be used for sorting."
)
if sort_by.sort_on == "SERIES":
expression = F(f"{sort_by.reference}_raw")
if sort_by.direction == "ASC":
expression = expression.asc(nulls_first=True)
else:
expression = expression.desc(nulls_last=True)
sorts.append(expression)
else:
field_obj = model.get_field_object(sort_by.reference)
field_type = field_obj["type"]
field_annotated_order_by = field_type.get_order(
field=field_obj["field"],
field_name=sort_by.reference,
order_direction=sort_by.direction,
)
if field_annotated_order_by.annotation is not None:
sort_annotations = {
**sort_annotations,
**field_annotated_order_by.annotation,
}
field_order_bys = field_annotated_order_by.order_bys
for field_order_by in field_order_bys:
sorts.append(field_order_by)
queryset = queryset.annotate(**sort_annotations)
def process_individual_result(result: dict): def process_individual_result(result: dict):
for agg_series in defined_agg_series: for agg_series in defined_agg_series:
key = f"{agg_series.field.db_column}_{agg_series.aggregation_type}" key = f"{agg_series.field.db_column}_{agg_series.aggregation_type}"
@ -495,9 +508,12 @@ class LocalBaserowGroupedAggregateRowsUserServiceType(
return result return result
if len(group_by_values) > 0: if len(group_by_values) > 0:
queryset = queryset.annotate(**combined_agg_dict)[ queryset = queryset.annotate(**combined_agg_dict)
queryset = queryset.order_by(*sorts)
queryset = queryset[
: settings.BASEROW_ENTERPRISE_GROUPED_AGGREGATE_SERVICE_MAX_AGG_BUCKETS : settings.BASEROW_ENTERPRISE_GROUPED_AGGREGATE_SERVICE_MAX_AGG_BUCKETS
] ]
results = [process_individual_result(result) for result in queryset] results = [process_individual_result(result) for result in queryset]
else: else:
results = queryset.aggregate(**combined_agg_dict) results = queryset.aggregate(**combined_agg_dict)

View file

@ -0,0 +1,63 @@
# Generated by Django 5.0.9 on 2025-03-03 02:31
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"baserow_enterprise",
"0041_alter_localbaserowtableserviceaggregationseries_field",
),
("core", "0094_alter_importexportresource_size"),
]
operations = [
migrations.CreateModel(
name="LocalBaserowTableServiceAggregationSortBy",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"sort_on",
models.CharField(
choices=[
("SERIES", "Series"),
("GROUP_BY", "Group by"),
("PRIMARY", "Primary"),
],
max_length=255,
),
),
("reference", models.CharField(max_length=255)),
(
"direction",
models.CharField(
choices=[("ASC", "Ascending"), ("DESC", "Descending")],
max_length=255,
),
),
("order", models.PositiveIntegerField()),
(
"service",
models.ForeignKey(
help_text="The service which this aggregation series belongs to.",
on_delete=django.db.models.deletion.CASCADE,
related_name="service_aggregation_sorts",
to="core.service",
),
),
],
options={
"ordering": ("order", "id"),
},
),
]

View file

@ -8,3 +8,9 @@ class ServiceAggregationSeriesDict(TypedDict):
class ServiceAggregationGroupByDict(TypedDict): class ServiceAggregationGroupByDict(TypedDict):
field_id: int field_id: int
class ServiceAggregationSortByDict(TypedDict):
sort_on: str
reference: str
direction: str

View file

@ -4,14 +4,12 @@ from rest_framework.status import HTTP_200_OK
from baserow.contrib.database.rows.handler import RowHandler from baserow.contrib.database.rows.handler import RowHandler
from baserow.contrib.database.views.models import SORT_ORDER_ASC from baserow.contrib.database.views.models import SORT_ORDER_ASC
from baserow.contrib.integrations.local_baserow.models import (
LocalBaserowTableServiceSort,
)
from baserow.test_utils.helpers import AnyDict, AnyInt from baserow.test_utils.helpers import AnyDict, AnyInt
from baserow_enterprise.integrations.local_baserow.models import ( from baserow_enterprise.integrations.local_baserow.models import (
LocalBaserowGroupedAggregateRows, LocalBaserowGroupedAggregateRows,
LocalBaserowTableServiceAggregationGroupBy, LocalBaserowTableServiceAggregationGroupBy,
LocalBaserowTableServiceAggregationSeries, LocalBaserowTableServiceAggregationSeries,
LocalBaserowTableServiceAggregationSortBy,
) )
@ -39,6 +37,13 @@ def test_grouped_aggregate_rows_get_dashboard_data_sources(
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=data_source1.service, field=field_3, order=1 service=data_source1.service, field=field_3, order=1
) )
LocalBaserowTableServiceAggregationSortBy.objects.create(
service=data_source1.service,
sort_on="GROUP_BY",
reference=f"field_{field_3.id}",
direction="ASC",
order=1,
)
enterprise_data_fixture.create_local_baserow_table_service_sort( enterprise_data_fixture.create_local_baserow_table_service_sort(
service=data_source1.service, service=data_source1.service,
field=field_3, field=field_3,
@ -74,13 +79,12 @@ def test_grouped_aggregate_rows_get_dashboard_data_sources(
"dashboard_id": dashboard.id, "dashboard_id": dashboard.id,
"filter_type": "AND", "filter_type": "AND",
"filters": [], "filters": [],
"sortings": [ "aggregation_sorts": [
{ {
"field": field_3.id, "sort_on": "GROUP_BY",
"id": AnyInt(), "reference": f"field_{field_3.id}",
"trashed": False, "direction": "ASC",
"order": 2, "order": 1,
"order_by": "ASC",
} }
], ],
"id": data_source1.id, "id": data_source1.id,
@ -138,7 +142,13 @@ def test_grouped_aggregate_rows_update_data_source(api_client, enterprise_data_f
{"field_id": field_2.id, "aggregation_type": "sum"}, {"field_id": field_2.id, "aggregation_type": "sum"},
], ],
"aggregation_group_bys": [{"field_id": field_3.id}], "aggregation_group_bys": [{"field_id": field_3.id}],
"sortings": [{"field": field.id}], "aggregation_sorts": [
{
"sort_on": "SERIES",
"reference": f"field_{field.id}_sum",
"direction": "ASC",
}
],
}, },
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
@ -164,13 +174,12 @@ def test_grouped_aggregate_rows_update_data_source(api_client, enterprise_data_f
assert response_json["aggregation_group_bys"] == [ assert response_json["aggregation_group_bys"] == [
{"field_id": field_3.id, "order": 0} {"field_id": field_3.id, "order": 0}
] ]
assert response_json["sortings"] == [ assert response_json["aggregation_sorts"] == [
{ {
"id": AnyInt(), "sort_on": "SERIES",
"field": field.id, "reference": f"field_{field.id}_sum",
"trashed": False, "direction": "ASC",
"order": 0, "order": 0,
"order_by": "ASC",
} }
] ]
@ -212,11 +221,19 @@ def test_grouped_aggregate_rows_dispatch_dashboard_data_source(
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field, order=1 service=service, field=field, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_3, order=1, order_by="ASC" service=service,
sort_on="SERIES",
reference=f"field_{field_3.id}_sum",
order=1,
direction="ASC",
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_2, order=2, order_by="DESC" service=service,
sort_on="SERIES",
reference=f"field_{field_2.id}_sum",
order=2,
direction="DESC",
) )
RowHandler().create_rows( RowHandler().create_rows(

View file

@ -18,6 +18,7 @@ from baserow_enterprise.integrations.local_baserow.models import (
LocalBaserowGroupedAggregateRows, LocalBaserowGroupedAggregateRows,
LocalBaserowTableServiceAggregationGroupBy, LocalBaserowTableServiceAggregationGroupBy,
LocalBaserowTableServiceAggregationSeries, LocalBaserowTableServiceAggregationSeries,
LocalBaserowTableServiceAggregationSortBy,
) )
@ -317,8 +318,12 @@ def test_create_grouped_aggregate_rows_service_sort_by_field_outside_of_series_g
{"field_id": field.id, "aggregation_type": "sum"}, {"field_id": field.id, "aggregation_type": "sum"},
], ],
"service_aggregation_group_bys": [{"field_id": field.id}], "service_aggregation_group_bys": [{"field_id": field.id}],
"service_sorts": [ "service_aggregation_sorts": [
{"field": field_2}, {
"sort_on": "SERIES",
"reference": f"field_{field_2.id}",
"direction": "ASC",
},
], ],
}, },
user, user,
@ -326,7 +331,7 @@ def test_create_grouped_aggregate_rows_service_sort_by_field_outside_of_series_g
with pytest.raises( with pytest.raises(
ValidationError, ValidationError,
match=f"The field with ID {field_2.id} cannot be used for sorting.", match=f"The reference sort 'field_{field_2.id}' cannot be used for sorting.",
): ):
ServiceHandler().create_service(service_type, **values) ServiceHandler().create_service(service_type, **values)
@ -354,8 +359,12 @@ def test_create_grouped_aggregate_rows_service_sort_by_primary_field_no_group_by
{"field_id": field.id, "aggregation_type": "sum"}, {"field_id": field.id, "aggregation_type": "sum"},
], ],
"service_aggregation_group_bys": [], "service_aggregation_group_bys": [],
"service_sorts": [ "service_aggregation_sorts": [
{"field": field_2}, {
"sort_on": "PRIMARY",
"reference": f"field_{field_2.id}",
"direction": "ASC",
},
], ],
}, },
user, user,
@ -363,7 +372,7 @@ def test_create_grouped_aggregate_rows_service_sort_by_primary_field_no_group_by
with pytest.raises( with pytest.raises(
ValidationError, ValidationError,
match=f"The field with ID {field_2.id} cannot be used for sorting.", match=f"The reference sort 'field_{field_2.id}' cannot be used for sorting.",
): ):
ServiceHandler().create_service(service_type, **values) ServiceHandler().create_service(service_type, **values)
@ -389,8 +398,12 @@ def test_create_grouped_aggregate_rows_service_sort_by_primary_field_with_group_
"integration_id": integration.id, "integration_id": integration.id,
"service_aggregation_series": [], "service_aggregation_series": [],
"service_aggregation_group_bys": [{"field_id": field_2.id}], "service_aggregation_group_bys": [{"field_id": field_2.id}],
"service_sorts": [ "service_aggregation_sorts": [
{"field": field}, {
"sort_on": "PRIMARY",
"reference": f"field_{field.id}",
"direction": "ASC",
},
], ],
}, },
user, user,
@ -398,7 +411,7 @@ def test_create_grouped_aggregate_rows_service_sort_by_primary_field_with_group_
with pytest.raises( with pytest.raises(
ValidationError, ValidationError,
match=f"The field with ID {field.id} cannot be used for sorting.", match=f"The reference sort 'field_{field.id}' cannot be used for sorting.",
): ):
ServiceHandler().create_service(service_type, **values) ServiceHandler().create_service(service_type, **values)
@ -765,8 +778,12 @@ def test_update_grouped_aggregate_rows_service_sort_by_field_outside_of_series_g
{"field_id": field.id, "aggregation_type": "sum"}, {"field_id": field.id, "aggregation_type": "sum"},
], ],
"service_aggregation_group_bys": [{"field_id": field.id}], "service_aggregation_group_bys": [{"field_id": field.id}],
"service_sorts": [ "service_aggregation_sorts": [
{"field": field_2}, {
"sort_on": "GROUP_BY",
"reference": f"field_{field_2.id}",
"direction": "ASC",
},
], ],
}, },
user, user,
@ -774,7 +791,7 @@ def test_update_grouped_aggregate_rows_service_sort_by_field_outside_of_series_g
with pytest.raises( with pytest.raises(
ValidationError, ValidationError,
match=f"The field with ID {field_2.id} cannot be used for sorting.", match=f"The reference sort 'field_{field_2.id}' cannot be used for sorting.",
): ):
ServiceHandler().update_service(service_type, service=service, **values) ServiceHandler().update_service(service_type, service=service, **values)
@ -808,8 +825,12 @@ def test_update_grouped_aggregate_rows_service_sort_by_primary_field_no_group_by
{"field_id": field.id, "aggregation_type": "sum"}, {"field_id": field.id, "aggregation_type": "sum"},
], ],
"service_aggregation_group_bys": [], "service_aggregation_group_bys": [],
"service_sorts": [ "service_aggregation_sorts": [
{"field": field_2}, {
"sort_on": "PRIMARY",
"reference": f"field_{field_2.id}",
"direction": "ASC",
},
], ],
}, },
user, user,
@ -817,7 +838,7 @@ def test_update_grouped_aggregate_rows_service_sort_by_primary_field_no_group_by
with pytest.raises( with pytest.raises(
ValidationError, ValidationError,
match=f"The field with ID {field_2.id} cannot be used for sorting.", match=f"The reference sort 'field_{field_2.id}' cannot be used for sorting.",
): ):
ServiceHandler().update_service(service_type, service=service, **values) ServiceHandler().update_service(service_type, service=service, **values)
@ -849,8 +870,12 @@ def test_update_grouped_aggregate_rows_service_sort_by_primary_field_with_group_
"integration_id": integration.id, "integration_id": integration.id,
"service_aggregation_series": [], "service_aggregation_series": [],
"service_aggregation_group_bys": [{"field_id": field_2.id}], "service_aggregation_group_bys": [{"field_id": field_2.id}],
"service_sorts": [ "service_aggregation_sorts": [
{"field": field}, {
"sort_on": "PRIMARY",
"reference": f"field_{field.id}",
"direction": "ASC",
},
], ],
}, },
user, user,
@ -858,7 +883,7 @@ def test_update_grouped_aggregate_rows_service_sort_by_primary_field_with_group_
with pytest.raises( with pytest.raises(
ValidationError, ValidationError,
match=f"The field with ID {field.id} cannot be used for sorting.", match=f"The reference sort 'field_{field.id}' cannot be used for sorting.",
): ):
ServiceHandler().update_service(service_type, service=service, **values) ServiceHandler().update_service(service_type, service=service, **values)
@ -887,8 +912,12 @@ def test_update_grouped_aggregate_rows_service_reset_after_table_change(data_fix
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field, order=1 service=service, field=field, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field, order=2, order_by="ASC" service=service,
sort_on="SERIES",
reference=f"field_{field.id}_sum",
order=2,
direction="ASC",
) )
values = service_type.prepare_values( values = service_type.prepare_values(
@ -911,7 +940,7 @@ def test_update_grouped_aggregate_rows_service_reset_after_table_change(data_fix
assert service.view is None assert service.view is None
assert service.service_aggregation_series.all().count() == 0 assert service.service_aggregation_series.all().count() == 0
assert service.service_aggregation_group_bys.all().count() == 0 assert service.service_aggregation_group_bys.all().count() == 0
assert service.service_sorts.all().count() == 0 assert service.service_aggregation_sorts.all().count() == 0
@pytest.mark.django_db @pytest.mark.django_db
@ -1548,11 +1577,19 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_series_with_group_by(
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field, order=1 service=service, field=field, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_3, order=1, order_by="ASC" service=service,
sort_on="SERIES",
reference=f"field_{field_3.id}_sum",
order=1,
direction="ASC",
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_2, order=2, order_by="DESC" service=service,
sort_on="SERIES",
reference=f"field_{field_2.id}_sum",
order=2,
direction="DESC",
) )
RowHandler().create_rows( RowHandler().create_rows(
@ -1682,11 +1719,19 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_series_with_group_by_ro
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=None, order=1 service=service, field=None, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_3, order=1, order_by="ASC" service=service,
sort_on="SERIES",
reference=f"field_{field_3.id}_sum",
order=1,
direction="ASC",
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_2, order=2, order_by="DESC" service=service,
sort_on="SERIES",
reference=f"field_{field_2.id}_sum",
order=2,
direction="DESC",
) )
RowHandler().create_rows( RowHandler().create_rows(
@ -1875,8 +1920,12 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_group_by_field(data_fix
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field, order=1 service=service, field=field, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field, order=1, order_by="ASC" service=service,
sort_on="GROUP_BY",
reference=f"field_{field.id}",
order=1,
direction="ASC",
) )
RowHandler().create_rows( RowHandler().create_rows(
@ -1997,8 +2046,12 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_group_by_row_id(data_fi
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=None, order=1 service=service, field=None, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field, order=1, order_by="ASC" service=service,
sort_on="GROUP_BY",
reference=f"field_{field.id}",
order=1,
direction="ASC",
) )
RowHandler().create_rows( RowHandler().create_rows(
@ -2095,15 +2148,19 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_field_outside_series_or
LocalBaserowTableServiceAggregationSeries.objects.create( LocalBaserowTableServiceAggregationSeries.objects.create(
service=service, field=field, aggregation_type="sum", order=2 service=service, field=field, aggregation_type="sum", order=2
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_2, order=1, order_by="ASC" service=service,
sort_on="GROUP_BY",
reference=f"field_{field_2.id}",
order=1,
direction="ASC",
) )
dispatch_context = FakeDispatchContext() dispatch_context = FakeDispatchContext()
with pytest.raises( with pytest.raises(
ServiceImproperlyConfigured, ServiceImproperlyConfigured,
match=f"The field with ID {field_2.id} cannot be used for sorting.", match=f"The sort reference 'field_{field_2.id}' cannot be used for sorting.",
): ):
ServiceHandler().dispatch_service(service, dispatch_context) ServiceHandler().dispatch_service(service, dispatch_context)
@ -2130,15 +2187,19 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_primary_field_no_group_
LocalBaserowTableServiceAggregationSeries.objects.create( LocalBaserowTableServiceAggregationSeries.objects.create(
service=service, field=field_2, aggregation_type="sum", order=2 service=service, field=field_2, aggregation_type="sum", order=2
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field, order=2, order_by="ASC" service=service,
sort_on="PRIMARY",
reference=f"field_{field.id}",
order=2,
direction="ASC",
) )
dispatch_context = FakeDispatchContext() dispatch_context = FakeDispatchContext()
with pytest.raises( with pytest.raises(
ServiceImproperlyConfigured, ServiceImproperlyConfigured,
match=f"The field with ID {field.id} cannot be used for sorting.", match=f"The sort reference 'field_{field.id}' cannot be used for sorting.",
): ):
ServiceHandler().dispatch_service(service, dispatch_context) ServiceHandler().dispatch_service(service, dispatch_context)
@ -2168,15 +2229,19 @@ def test_grouped_aggregate_rows_service_dispatch_sort_by_primary_field_group_by_
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field_2, order=1 service=service, field=field_2, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field, order=2, order_by="ASC" service=service,
sort_on="PRIMARY",
reference=f"field_{field.id}",
order=2,
direction="ASC",
) )
dispatch_context = FakeDispatchContext() dispatch_context = FakeDispatchContext()
with pytest.raises( with pytest.raises(
ServiceImproperlyConfigured, ServiceImproperlyConfigured,
match=f"The field with ID {field.id} cannot be used for sorting.", match=f"The sort reference 'field_{field.id}' cannot be used for sorting.",
): ):
ServiceHandler().dispatch_service(service, dispatch_context) ServiceHandler().dispatch_service(service, dispatch_context)
@ -2338,8 +2403,12 @@ def test_grouped_aggregate_rows_service_dispatch_max_buckets_sort_on_group_by_fi
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field_2, order=1 service=service, field=field_2, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_2, order=1, order_by="ASC" service=service,
sort_on="GROUP_BY",
reference=f"field_{field_2.id}",
order=1,
direction="ASC",
) )
RowHandler().create_rows( RowHandler().create_rows(
@ -2425,8 +2494,12 @@ def test_grouped_aggregate_rows_service_dispatch_max_buckets_sort_on_series(
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=field_2, order=1 service=service, field=field_2, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field, order=1, order_by="ASC" service=service,
sort_on="SERIES",
reference=f"field_{field.id}_sum",
order=1,
direction="ASC",
) )
RowHandler().create_rows( RowHandler().create_rows(
@ -2512,8 +2585,12 @@ def test_grouped_aggregate_rows_service_dispatch_max_buckets_sort_on_primary_fie
LocalBaserowTableServiceAggregationGroupBy.objects.create( LocalBaserowTableServiceAggregationGroupBy.objects.create(
service=service, field=None, order=1 service=service, field=None, order=1
) )
LocalBaserowTableServiceSort.objects.create( LocalBaserowTableServiceAggregationSortBy.objects.create(
service=service, field=field_2, order=1, order_by="ASC" service=service,
sort_on="GROUP_BY",
reference=f"field_{field_2.id}",
order=1,
direction="ASC",
) )
rows = RowHandler().create_rows( rows = RowHandler().create_rows(

View file

@ -4,30 +4,30 @@
class="margin-bottom-2" class="margin-bottom-2"
> >
<Dropdown <Dropdown
:value="sortByField" :value="sortReference"
:show-search="true" :show-search="true"
fixed-items fixed-items
class="margin-bottom-1" class="margin-bottom-1"
:error="v$.sortByField?.$error || false" :error="v$.sortReference?.$error || false"
@change="sortByFieldChangedByUser($event)" @change="sortReferenceChangedByUser($event)"
> >
<DropdownItem <DropdownItem
:name="$t('aggregationSortByForm.none')" :name="$t('aggregationSortByForm.none')"
:value="null" :value="null"
></DropdownItem> ></DropdownItem>
<DropdownItem <DropdownItem
v-for="field in allowedSortFields" v-for="allowedSortReference in allowedSortReferences"
:key="field.id" :key="allowedSortReference.reference"
:name="field.name" :name="allowedSortReference.name"
:value="field.id" :value="allowedSortReference.reference"
:icon="fieldIconClass(field)" :icon="fieldIconClass(allowedSortReference.field)"
> >
</DropdownItem> </DropdownItem>
</Dropdown> </Dropdown>
<SegmentControl <SegmentControl
:active-index="orderByIndex" :active-index="orderDirectionIndex"
:segments="orderByOptions" :segments="orderDirectionOptions"
:initial-active-index="orderByIndex" :initial-active-index="orderDirectionIndex"
@update:activeIndex="orderByChangedByUser" @update:activeIndex="orderByChangedByUser"
></SegmentControl> ></SegmentControl>
</FormSection> </FormSection>
@ -46,7 +46,7 @@ const includesIfSet = (array) => (value) => {
export default { export default {
name: 'AggregationSortByForm', name: 'AggregationSortByForm',
props: { props: {
allowedSortFields: { allowedSortReferences: {
type: Array, type: Array,
required: true, required: true,
}, },
@ -60,12 +60,12 @@ export default {
}, },
data() { data() {
return { return {
sortByField: null, sortReference: null,
orderByIndex: 0, orderDirectionIndex: 0,
} }
}, },
computed: { computed: {
orderByOptions() { orderDirectionOptions() {
return [ return [
{ label: this.$t('aggregationSortByForm.ascending'), value: 'ASC' }, { label: this.$t('aggregationSortByForm.ascending'), value: 'ASC' },
{ label: this.$t('aggregationSortByForm.descending'), value: 'DESC' }, { label: this.$t('aggregationSortByForm.descending'), value: 'DESC' },
@ -76,13 +76,13 @@ export default {
aggregationSorts: { aggregationSorts: {
handler(aggregationSorts) { handler(aggregationSorts) {
if (aggregationSorts.length !== 0) { if (aggregationSorts.length !== 0) {
this.sortByField = aggregationSorts[0].field this.sortReference = aggregationSorts[0].reference
this.orderByIndex = this.orderByOptions.findIndex( this.orderDirectionIndex = this.orderDirectionOptions.findIndex(
(item) => item.value === aggregationSorts[0].order_by (item) => item.value === aggregationSorts[0].direction
) )
} else { } else {
this.sortByField = null this.sortReference = null
this.orderByIndex = 0 this.orderDirectionIndex = 0
} }
}, },
immediate: true, immediate: true,
@ -94,27 +94,38 @@ export default {
validations() { validations() {
const self = this const self = this
return { return {
sortByField: { sortReference: {
isValidSortFieldId: (value) => { isValidSortReference: (value) => {
const ids = self.allowedSortFields.map((item) => item.id) const sortReferences = self.allowedSortReferences.map(
return includesIfSet(ids)(value) (item) => item.reference
)
return includesIfSet(sortReferences)(value)
}, },
}, },
} }
}, },
methods: { methods: {
sortByFieldChangedByUser(value) { sortReferenceChangedByUser(value) {
this.sortByField = value this.sortReference = value
this.$emit('value-changed', { this.emitValue()
field: value,
order_by: this.orderByOptions[this.orderByIndex].value,
})
}, },
orderByChangedByUser(index) { orderByChangedByUser(index) {
this.orderByIndex = index this.orderDirectionIndex = index
this.emitValue()
},
emitValue() {
if (this.sortReference === null) {
this.$emit('value-changed', null)
return
}
const chosenReference = this.allowedSortReferences.find(
(item) => item.reference === this.sortReference
)
this.$emit('value-changed', { this.$emit('value-changed', {
field: this.sortByField, sort_on: chosenReference.sort_on,
order_by: this.orderByOptions[index].value, reference: chosenReference.reference,
direction: this.orderDirectionOptions[this.orderDirectionIndex].value,
}) })
}, },
fieldIconClass(field) { fieldIconClass(field) {

View file

@ -101,8 +101,8 @@
</AggregationGroupByForm> </AggregationGroupByForm>
<AggregationSortByForm <AggregationSortByForm
v-if="values.table_id && !fieldHasErrors('table_id')" v-if="values.table_id && !fieldHasErrors('table_id')"
:aggregation-sorts="values.sortings" :aggregation-sorts="values.aggregation_sorts"
:allowed-sort-fields="allowedSortFields" :allowed-sort-references="allowedSortReferences"
@value-changed="onSortByUpdated($event)" @value-changed="onSortByUpdated($event)"
> >
</AggregationSortByForm> </AggregationSortByForm>
@ -161,14 +161,14 @@ export default {
'view_id', 'view_id',
'aggregation_series', 'aggregation_series',
'aggregation_group_bys', 'aggregation_group_bys',
'sortings', 'aggregation_sorts',
], ],
values: { values: {
table_id: null, table_id: null,
view_id: null, view_id: null,
aggregation_series: [], aggregation_series: [],
aggregation_group_bys: [], aggregation_group_bys: [],
sortings: [], aggregation_sorts: [],
}, },
tableLoading: false, tableLoading: false,
databaseSelectedId: null, databaseSelectedId: null,
@ -201,6 +201,9 @@ export default {
tableFields() { tableFields() {
return this.tableSelected?.fields || [] return this.tableSelected?.fields || []
}, },
primaryTableField() {
return this.tableFields.find((item) => item.primary === true)
},
tableFieldIds() { tableFieldIds() {
return this.tableFields.map((field) => field.id) return this.tableFields.map((field) => field.id)
}, },
@ -214,17 +217,35 @@ export default {
tableViewIds() { tableViewIds() {
return this.tableViews.map((view) => view.id) return this.tableViews.map((view) => view.id)
}, },
allowedSortFields() { allowedSortReferences() {
const seriesFieldIds = this.values.aggregation_series.map( const seriesSortReferences = this.values.aggregation_series
(item) => item.field_id .filter((item) => item.field_id && item.aggregation_type)
.map((item) => {
const field = this.getTableFieldById(item.field_id)
return {
sort_on: 'SERIES',
reference: `field_${item.field_id}_${item.aggregation_type}`,
field,
name: `${field.name} (${this.getAggregationName(
item.aggregation_type
)})`,
}
})
const groupBySortReferences = this.values.aggregation_group_bys.map(
(item) => {
const field =
item.field_id === null
? this.primaryTableField
: this.getTableFieldById(item.field_id)
return {
sort_on: 'GROUP_BY',
reference: `field_${field.id}`,
field,
name: field.name,
}
}
) )
const groupByFieldIds = this.values.aggregation_group_bys.map( return seriesSortReferences.concat(groupBySortReferences)
(item) => item.field_id
)
const allowedFieldIds = seriesFieldIds.concat(groupByFieldIds)
return this.tableFields.filter((item) => {
return allowedFieldIds.includes(item.id)
})
}, },
}, },
watch: { watch: {
@ -280,22 +301,44 @@ export default {
} }
}, },
methods: { methods: {
getTableFieldById(fieldId) {
return this.tableFields.find((tableField) => {
return tableField.id === fieldId
})
},
getAggregationName(aggregationType) {
const aggType = this.$registry.get('groupedAggregation', aggregationType)
return aggType.getName()
},
changeTableId(tableId) { changeTableId(tableId) {
this.values.table_id = tableId this.values.table_id = tableId
this.values.view_id = null this.values.view_id = null
this.values.aggregation_series = [] this.values.aggregation_series = []
this.values.aggregation_group_bys = [] this.values.aggregation_group_bys = []
this.values.sortings = [] this.values.aggregation_sorts = []
this.v$.values.table_id.$touch() this.v$.values.table_id.$touch()
}, },
addSeries() { async addSeries() {
this.setEmitValues(false)
this.values.aggregation_series.push({ this.values.aggregation_series.push({
field_id: null, field_id: null,
aggregation_type: '', aggregation_type: '',
}) })
this.$emit('values-changed', {
aggregation_series: this.values.aggregation_series,
})
await this.$nextTick()
this.setEmitValues(true)
}, },
deleteSeries(index) { async deleteSeries(index) {
this.values.aggregation_series.splice(index, 1) this.setEmitValues(false)
const updatedAggregationSeries = this.values.aggregation_series
updatedAggregationSeries.splice(index, 1)
this.$emit('values-changed', {
aggregation_series: updatedAggregationSeries,
})
await this.$nextTick()
this.setEmitValues(true)
}, },
onAggregationSeriesUpdated(index, aggregationSeriesValues) { onAggregationSeriesUpdated(index, aggregationSeriesValues) {
const updatedAggregationSeries = this.values.aggregation_series const updatedAggregationSeries = this.values.aggregation_series
@ -315,10 +358,10 @@ export default {
aggregation_group_bys: aggregationGroupBys, aggregation_group_bys: aggregationGroupBys,
}) })
}, },
onSortByUpdated(sortBy) { onSortByUpdated(sort) {
const aggregationSorts = sortBy.field !== null ? [sortBy] : [] const aggregationSorts = sort !== null ? [sort] : []
this.$emit('values-changed', { this.$emit('values-changed', {
sortings: aggregationSorts, aggregation_sorts: aggregationSorts,
}) })
}, },
}, },