Skip to content

Commit 479e616

Browse files
authored
feat: add columns layout to grouped grid views (baserow#6022)
* feat: add columns layout to grouped grid views * test: strengthen Columns layout coverage * fix: remove doubled vertical border on group column spans The group-by divider already draws a full-height line at each level boundary, so the span's own border-right rendered a second adjacent line in the body but not in the header. * chore: renumber group_by_layout migration after rebase Develop added 0221 and 0222 in the meantime, so the branch migration forked the graph into two leaf nodes. * refactor: rename banner group layout to section
1 parent 22cd0ed commit 479e616

46 files changed

Lines changed: 3746 additions & 263 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from django.db import migrations, models
2+
3+
4+
class Migration(migrations.Migration):
5+
dependencies = [
6+
("database", "0222_button_field_start_workflow_action"),
7+
]
8+
9+
operations = [
10+
migrations.AddField(
11+
model_name="gridview",
12+
name="group_by_layout",
13+
field=models.CharField(
14+
choices=[("section", "Section"), ("column", "Column")],
15+
db_default="section",
16+
default="section",
17+
max_length=10,
18+
help_text="How grouped rows are presented: sections with a header above "
19+
"each group, or one column per group-by level beside the rows.",
20+
),
21+
),
22+
]

backend/src/baserow/contrib/database/views/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,10 @@ class RowHeightSizes(models.TextChoices):
610610
medium = "medium"
611611
large = "large"
612612

613+
class GroupByLayouts(models.TextChoices):
614+
section = "section"
615+
column = "column"
616+
613617
# `field_options` is a very misleading name
614618
# it should probably be more like `fields_with_field_options`
615619
# since this field will return instances of `Field` not of
@@ -628,6 +632,14 @@ class RowHeightSizes(models.TextChoices):
628632
# Number of frozen (pinned) columns including the primary field. Max defined in
629633
# the serializer.
630634
frozen_column_count = models.PositiveSmallIntegerField(default=1, db_default=1)
635+
group_by_layout = models.CharField(
636+
choices=GroupByLayouts.choices,
637+
default=GroupByLayouts.section,
638+
db_default=GroupByLayouts.section,
639+
max_length=10,
640+
help_text="How grouped rows are presented: sections with a header above each "
641+
"group, or one column per group-by level beside the rows.",
642+
)
631643

632644

633645
class GridViewFieldOptionsManager(models.Manager):

backend/src/baserow/contrib/database/views/view_types.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,17 @@ class GridViewType(ViewType):
8585
has_public_info = True
8686
can_group_by = True
8787
when_shared_publicly_requires_realtime_events = True
88-
allowed_fields = ["row_identifier_type", "row_height_size", "frozen_column_count"]
88+
allowed_fields = [
89+
"row_identifier_type",
90+
"row_height_size",
91+
"frozen_column_count",
92+
"group_by_layout",
93+
]
8994
copyable_view_attributes = [
9095
"row_height_size",
9196
"frozen_column_count",
9297
"row_identifier_type",
98+
"group_by_layout",
9399
]
94100
field_options_allowed_fields = [
95101
"width",
@@ -102,6 +108,7 @@ class GridViewType(ViewType):
102108
"row_identifier_type",
103109
"row_height_size",
104110
"frozen_column_count",
111+
"group_by_layout",
105112
]
106113
serializer_field_overrides = {
107114
"frozen_column_count": serializers.IntegerField(
@@ -142,6 +149,7 @@ def export_serialized(
142149
serialized["row_identifier_type"] = grid.row_identifier_type
143150
serialized["row_height_size"] = grid.row_height_size
144151
serialized["frozen_column_count"] = grid.frozen_column_count
152+
serialized["group_by_layout"] = grid.group_by_layout
145153

146154
serialized_field_options = []
147155
for field_option in grid.get_field_options():

backend/tests/baserow/contrib/database/airtable/test_airtable_handler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ def test_to_baserow_database_export():
641641
"row_identifier_type": "count",
642642
"row_height_size": "small",
643643
"frozen_column_count": 1,
644+
"group_by_layout": "section",
644645
"filter_type": "AND",
645646
"filters_disabled": False,
646647
"filters": [],

backend/tests/baserow/contrib/database/airtable/test_airtable_view_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ def test_import_grid_view():
263263
"public": False,
264264
"row_height_size": "medium",
265265
"frozen_column_count": 1,
266+
"group_by_layout": "section",
266267
"row_identifier_type": "count",
267268
"sortings": [],
268269
"type": "grid",

backend/tests/baserow/contrib/database/api/views/grid/test_grid_view_views.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3482,6 +3482,7 @@ def test_get_public_grid_view(api_client, data_fixture):
34823482
"row_identifier_type": grid_view.row_identifier_type,
34833483
"row_height_size": grid_view.row_height_size,
34843484
"frozen_column_count": 1,
3485+
"group_by_layout": grid_view.group_by_layout,
34853486
"show_logo": True,
34863487
"allow_public_export": False,
34873488
"ownership_type": "collaborative",
@@ -5820,3 +5821,36 @@ def test_list_rows_group_by_alone_applies_ordering(api_client, data_fixture):
58205821
results = response.json()["results"]
58215822
result_ids = [r["id"] for r in results]
58225823
assert result_ids == [row_a.id, row_b.id, row_c.id]
5824+
5825+
5826+
@pytest.mark.django_db
5827+
def test_update_grid_view_group_by_layout(api_client, data_fixture):
5828+
user, token = data_fixture.create_user_and_token()
5829+
table = data_fixture.create_database_table(user=user)
5830+
grid_view = data_fixture.create_grid_view(table=table)
5831+
url = reverse("api:database:views:item", kwargs={"view_id": grid_view.id})
5832+
5833+
response = api_client.get(url, format="json", HTTP_AUTHORIZATION=f"JWT {token}")
5834+
assert response.status_code == HTTP_200_OK
5835+
assert response.json()["group_by_layout"] == "section"
5836+
5837+
for group_by_layout in ("column", "section"):
5838+
response = api_client.patch(
5839+
url,
5840+
{"group_by_layout": group_by_layout},
5841+
format="json",
5842+
HTTP_AUTHORIZATION=f"JWT {token}",
5843+
)
5844+
assert response.status_code == HTTP_200_OK
5845+
assert response.json()["group_by_layout"] == group_by_layout
5846+
grid_view.refresh_from_db()
5847+
assert grid_view.group_by_layout == group_by_layout
5848+
5849+
response = api_client.patch(
5850+
url,
5851+
{"group_by_layout": "vertical"},
5852+
format="json",
5853+
HTTP_AUTHORIZATION=f"JWT {token}",
5854+
)
5855+
assert response.status_code == HTTP_400_BAD_REQUEST
5856+
assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION"

backend/tests/baserow/contrib/database/api/views/test_view_copy_configuration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def test_copy_view_configuration(api_client, data_fixture):
2222
filter_type="OR",
2323
row_height_size="large",
2424
frozen_column_count=2,
25+
group_by_layout="column",
2526
)
2627
dest_view = data_fixture.create_grid_view(table=table)
2728

@@ -58,6 +59,7 @@ def test_copy_view_configuration(api_client, data_fixture):
5859
assert response_json["filter_type"] == "OR"
5960
assert response_json["row_height_size"] == "large"
6061
assert response_json["frozen_column_count"] == 2
62+
assert response_json["group_by_layout"] == "column"
6163
assert len(response_json["filters"]) == 1
6264
assert response_json["filters"][0]["value"] == "a"
6365
assert len(response_json["filter_groups"]) == 1

backend/tests/baserow/contrib/database/api/views/test_view_views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,7 @@ def test_user_with_password_can_get_info_about_a_public_password_protected_view(
10191019
"row_identifier_type": grid_view.row_identifier_type,
10201020
"row_height_size": grid_view.row_height_size,
10211021
"frozen_column_count": 1,
1022+
"group_by_layout": grid_view.group_by_layout,
10221023
"show_logo": grid_view.show_logo,
10231024
"allow_public_export": grid_view.allow_public_export,
10241025
"ownership_type": "collaborative",
@@ -1051,6 +1052,7 @@ def test_user_with_password_can_get_info_about_a_public_password_protected_view(
10511052
"row_identifier_type": grid_view.row_identifier_type,
10521053
"row_height_size": grid_view.row_height_size,
10531054
"frozen_column_count": 1,
1055+
"group_by_layout": grid_view.group_by_layout,
10541056
"show_logo": grid_view.show_logo,
10551057
"allow_public_export": grid_view.allow_public_export,
10561058
"ownership_type": "collaborative",

backend/tests/baserow/contrib/database/view/test_view_configuration_copy.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def test_copy_view_configuration_field_options_and_row_height(data_fixture):
163163
row_height_size="large",
164164
frozen_column_count=3,
165165
row_identifier_type="count",
166+
group_by_layout="column",
166167
)
167168
dest_view = data_fixture.create_grid_view(table=table, row_height_size="small")
168169

@@ -184,6 +185,7 @@ def test_copy_view_configuration_field_options_and_row_height(data_fixture):
184185
assert dest_view.row_height_size == "large"
185186
assert dest_view.frozen_column_count == 3
186187
assert dest_view.row_identifier_type == "count"
188+
assert dest_view.group_by_layout == "column"
187189
dest_options = dest_view.gridviewfieldoptions_set.get(field=field)
188190
assert dest_options.hidden is True
189191
assert dest_options.width == 300

backend/tests/baserow/contrib/database/view/test_view_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_import_export_grid_view(data_fixture):
3939
filter_type="AND",
4040
filters_disabled=False,
4141
row_identifier_type="count",
42+
group_by_layout="column",
4243
)
4344
field = data_fixture.create_text_field(table=grid_view.table)
4445
imported_field = data_fixture.create_text_field(table=grid_view.table)
@@ -85,6 +86,7 @@ def test_import_export_grid_view(data_fixture):
8586
assert grid_view.filter_type == imported_grid_view.filter_type
8687
assert grid_view.filters_disabled == imported_grid_view.filters_disabled
8788
assert grid_view.row_identifier_type == imported_grid_view.row_identifier_type
89+
assert imported_grid_view.group_by_layout == "column"
8890
assert imported_grid_view.viewfilter_set.all().count() == 1
8991
assert imported_grid_view.viewsort_set.all().count() == 1
9092

0 commit comments

Comments
 (0)