mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-26 21:54:40 +00:00
Merge branch 'import-airtable-gallery-view' into 'develop'
Import Airtable gallery view See merge request baserow/baserow!3261
This commit is contained in:
commit
d64f70b09d
7 changed files with 480 additions and 25 deletions
backend
src/baserow/contrib/database
tests/baserow/contrib/database/airtable
changelog/entries/unreleased/feature
|
@ -1,6 +1,22 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from baserow.contrib.database.airtable.constants import (
|
||||||
|
AIRTABLE_GALLERY_VIEW_COVER_CROP_TYPE,
|
||||||
|
)
|
||||||
|
from baserow.contrib.database.airtable.import_report import (
|
||||||
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
|
SCOPE_VIEW,
|
||||||
|
AirtableImportReport,
|
||||||
|
)
|
||||||
from baserow.contrib.database.airtable.registry import AirtableViewType
|
from baserow.contrib.database.airtable.registry import AirtableViewType
|
||||||
from baserow.contrib.database.views.models import GridView, GridViewFieldOptions
|
from baserow.contrib.database.fields.field_types import FileFieldType
|
||||||
from baserow.contrib.database.views.view_types import GridViewType
|
from baserow.contrib.database.views.models import (
|
||||||
|
GalleryView,
|
||||||
|
GalleryViewFieldOptions,
|
||||||
|
GridView,
|
||||||
|
GridViewFieldOptions,
|
||||||
|
)
|
||||||
|
from baserow.contrib.database.views.view_types import GalleryViewType, GridViewType
|
||||||
from baserow.core.utils import get_value_at_path
|
from baserow.core.utils import get_value_at_path
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,3 +70,113 @@ class GridAirtableViewType(AirtableViewType):
|
||||||
view.get_field_options = lambda *args, **kwargs: field_options
|
view.get_field_options = lambda *args, **kwargs: field_options
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
|
||||||
|
|
||||||
|
class GalleryAirtableViewType(AirtableViewType):
|
||||||
|
type = "gallery"
|
||||||
|
baserow_view_type = GalleryViewType.type
|
||||||
|
|
||||||
|
def get_cover_column(
|
||||||
|
self,
|
||||||
|
field_mapping: dict,
|
||||||
|
view: GalleryView,
|
||||||
|
raw_airtable_table: dict,
|
||||||
|
raw_airtable_view_data: dict,
|
||||||
|
import_report: AirtableImportReport,
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Checks if the chosen coverColumnId is set, if the field exist, and if the
|
||||||
|
field is compatible with the cover type Baserow. If all is True, it returns
|
||||||
|
the referenced field id.
|
||||||
|
"""
|
||||||
|
|
||||||
|
cover_column_id = get_value_at_path(
|
||||||
|
raw_airtable_view_data, "metadata.gallery.coverColumnId", None
|
||||||
|
)
|
||||||
|
|
||||||
|
if not cover_column_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
cover_column = field_mapping.get(cover_column_id, None)
|
||||||
|
if cover_column is None:
|
||||||
|
import_report.add_failed(
|
||||||
|
view.name,
|
||||||
|
SCOPE_VIEW,
|
||||||
|
raw_airtable_table["name"],
|
||||||
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
|
f'View "{view.name}" cover column with id '
|
||||||
|
f'"{cover_column_id}" is not found.',
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cover_column["baserow_field_type"].type != FileFieldType.type:
|
||||||
|
import_report.add_failed(
|
||||||
|
view.name,
|
||||||
|
SCOPE_VIEW,
|
||||||
|
raw_airtable_table["name"],
|
||||||
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
|
f'View "{view.name}" cover column with id '
|
||||||
|
f'"{cover_column_id}" is not a file field.',
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
return cover_column_id
|
||||||
|
|
||||||
|
def prepare_view_object(
|
||||||
|
self,
|
||||||
|
field_mapping,
|
||||||
|
view: GalleryView,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
raw_airtable_view_data,
|
||||||
|
config,
|
||||||
|
import_report,
|
||||||
|
):
|
||||||
|
cover_column_id = self.get_cover_column(
|
||||||
|
field_mapping,
|
||||||
|
view,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view_data,
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
view.card_cover_image_field_id = cover_column_id
|
||||||
|
|
||||||
|
cover_fit_type = get_value_at_path(
|
||||||
|
raw_airtable_view_data, "metadata.gallery.coverFitType", None
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
cover_column_id
|
||||||
|
and cover_fit_type
|
||||||
|
and cover_fit_type != AIRTABLE_GALLERY_VIEW_COVER_CROP_TYPE
|
||||||
|
):
|
||||||
|
import_report.add_failed(
|
||||||
|
view.name,
|
||||||
|
SCOPE_VIEW,
|
||||||
|
raw_airtable_table["name"],
|
||||||
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
|
f'View "{view.name}" cover fit type "{cover_fit_type}" is not '
|
||||||
|
f'supported, so it defaulted to "crop"',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Map the columnOrder entries to the matching `GalleryViewFieldOptions`,
|
||||||
|
# and set that as `get_field_options`, so that it's correctly serialized
|
||||||
|
# exported.
|
||||||
|
field_options = []
|
||||||
|
column_orders = raw_airtable_view_data.get("columnOrder", None) or []
|
||||||
|
for index, column_order in enumerate(column_orders):
|
||||||
|
if column_order["columnId"] not in field_mapping:
|
||||||
|
continue
|
||||||
|
|
||||||
|
field_options.append(
|
||||||
|
GalleryViewFieldOptions(
|
||||||
|
id=f"{raw_airtable_view['id']}_columnOrder_{index}",
|
||||||
|
gallery_view_id=view.id,
|
||||||
|
field_id=column_order["columnId"],
|
||||||
|
hidden=not column_order.get("visibility", True),
|
||||||
|
order=index + 1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
view.get_field_options = lambda *args, **kwargs: field_options
|
||||||
|
|
||||||
|
return view
|
||||||
|
|
|
@ -104,3 +104,4 @@ AIRTABLE_DATE_FILTER_VALUE_MAP = {
|
||||||
"tomorrow": "{timeZone}??tomorrow",
|
"tomorrow": "{timeZone}??tomorrow",
|
||||||
"yesterday": "{timeZone}??yesterday",
|
"yesterday": "{timeZone}??yesterday",
|
||||||
}
|
}
|
||||||
|
AIRTABLE_GALLERY_VIEW_COVER_CROP_TYPE = "crop"
|
||||||
|
|
|
@ -19,6 +19,7 @@ from baserow.contrib.database.airtable.import_report import (
|
||||||
ERROR_TYPE_DATA_TYPE_MISMATCH,
|
ERROR_TYPE_DATA_TYPE_MISMATCH,
|
||||||
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
SCOPE_FIELD,
|
SCOPE_FIELD,
|
||||||
|
SCOPE_VIEW,
|
||||||
SCOPE_VIEW_COLOR,
|
SCOPE_VIEW_COLOR,
|
||||||
SCOPE_VIEW_FILTER,
|
SCOPE_VIEW_FILTER,
|
||||||
SCOPE_VIEW_GROUP_BY,
|
SCOPE_VIEW_GROUP_BY,
|
||||||
|
@ -681,6 +682,36 @@ class AirtableViewType(Instance):
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def _check_personal_or_locked(
|
||||||
|
self,
|
||||||
|
view_name: str,
|
||||||
|
raw_airtable_view: dict,
|
||||||
|
raw_airtable_table: dict,
|
||||||
|
import_report: AirtableImportReport,
|
||||||
|
) -> str:
|
||||||
|
if raw_airtable_view.get("personalForUserId", ""):
|
||||||
|
import_report.add_failed(
|
||||||
|
view_name,
|
||||||
|
SCOPE_VIEW,
|
||||||
|
raw_airtable_table["name"],
|
||||||
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
|
f'View "{view_name}" is personal, but was made collaborative because '
|
||||||
|
f"it can't be linked to a user. (Personal) was added to the name.",
|
||||||
|
)
|
||||||
|
view_name += " (Personal)"
|
||||||
|
|
||||||
|
if raw_airtable_view.get("lock", None):
|
||||||
|
import_report.add_failed(
|
||||||
|
view_name,
|
||||||
|
SCOPE_VIEW,
|
||||||
|
raw_airtable_table["name"],
|
||||||
|
ERROR_TYPE_UNSUPPORTED_FEATURE,
|
||||||
|
f'View "{view_name}" is locked, but was made collaborative because '
|
||||||
|
f"it Baserow does not support this yet.",
|
||||||
|
)
|
||||||
|
|
||||||
|
return view_name
|
||||||
|
|
||||||
def to_serialized_baserow_view(
|
def to_serialized_baserow_view(
|
||||||
self,
|
self,
|
||||||
field_mapping,
|
field_mapping,
|
||||||
|
@ -696,11 +727,16 @@ class AirtableViewType(Instance):
|
||||||
"The `baserow_view_type` must be implemented for the AirtableViewType."
|
"The `baserow_view_type` must be implemented for the AirtableViewType."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
view_name = raw_airtable_view["name"]
|
||||||
|
view_name = self._check_personal_or_locked(
|
||||||
|
view_name, raw_airtable_view, raw_airtable_table, import_report
|
||||||
|
)
|
||||||
|
|
||||||
view_type = view_type_registry.get(self.baserow_view_type)
|
view_type = view_type_registry.get(self.baserow_view_type)
|
||||||
view = view_type.model_class(
|
view = view_type.model_class(
|
||||||
id=raw_airtable_view["id"],
|
id=raw_airtable_view["id"],
|
||||||
pk=raw_airtable_view["id"],
|
pk=raw_airtable_view["id"],
|
||||||
name=raw_airtable_view["name"],
|
name=view_name,
|
||||||
order=raw_airtable_table["viewOrder"].index(raw_airtable_view["id"]) + 1,
|
order=raw_airtable_table["viewOrder"].index(raw_airtable_view["id"]) + 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -652,9 +652,13 @@ class DatabaseConfig(AppConfig):
|
||||||
airtable_column_type_registry.register(CountAirtableColumnType())
|
airtable_column_type_registry.register(CountAirtableColumnType())
|
||||||
airtable_column_type_registry.register(AutoNumberAirtableColumnType())
|
airtable_column_type_registry.register(AutoNumberAirtableColumnType())
|
||||||
|
|
||||||
from .airtable.airtable_view_types import GridAirtableViewType
|
from .airtable.airtable_view_types import (
|
||||||
|
GalleryAirtableViewType,
|
||||||
|
GridAirtableViewType,
|
||||||
|
)
|
||||||
|
|
||||||
airtable_view_type_registry.register(GridAirtableViewType())
|
airtable_view_type_registry.register(GridAirtableViewType())
|
||||||
|
airtable_view_type_registry.register(GalleryAirtableViewType())
|
||||||
|
|
||||||
from .airtable.airtable_filter_operators import (
|
from .airtable.airtable_filter_operators import (
|
||||||
AirtableContainsOperator,
|
AirtableContainsOperator,
|
||||||
|
|
|
@ -427,8 +427,8 @@ class GalleryViewType(ViewType):
|
||||||
|
|
||||||
serialized = super().export_serialized(gallery, cache, files_zip, storage)
|
serialized = super().export_serialized(gallery, cache, files_zip, storage)
|
||||||
|
|
||||||
if gallery.card_cover_image_field:
|
if gallery.card_cover_image_field_id:
|
||||||
serialized["card_cover_image_field_id"] = gallery.card_cover_image_field.id
|
serialized["card_cover_image_field_id"] = gallery.card_cover_image_field_id
|
||||||
|
|
||||||
serialized_field_options = []
|
serialized_field_options = []
|
||||||
for field_option in gallery.get_field_options():
|
for field_option in gallery.get_field_options():
|
||||||
|
|
|
@ -6,14 +6,15 @@ import pytest
|
||||||
|
|
||||||
from baserow.contrib.database.airtable.config import AirtableImportConfig
|
from baserow.contrib.database.airtable.config import AirtableImportConfig
|
||||||
from baserow.contrib.database.airtable.import_report import (
|
from baserow.contrib.database.airtable.import_report import (
|
||||||
|
SCOPE_VIEW,
|
||||||
SCOPE_VIEW_COLOR,
|
SCOPE_VIEW_COLOR,
|
||||||
SCOPE_VIEW_GROUP_BY,
|
SCOPE_VIEW_GROUP_BY,
|
||||||
SCOPE_VIEW_SORT,
|
SCOPE_VIEW_SORT,
|
||||||
AirtableImportReport,
|
AirtableImportReport,
|
||||||
)
|
)
|
||||||
from baserow.contrib.database.airtable.registry import airtable_view_type_registry
|
from baserow.contrib.database.airtable.registry import airtable_view_type_registry
|
||||||
from baserow.contrib.database.fields.field_types import TextFieldType
|
from baserow.contrib.database.fields.field_types import FileFieldType, TextFieldType
|
||||||
from baserow.contrib.database.fields.models import TextField
|
from baserow.contrib.database.fields.models import FileField, TextField
|
||||||
|
|
||||||
RAW_AIRTABLE_VIEW = {
|
RAW_AIRTABLE_VIEW = {
|
||||||
"id": "viwcpYeEpAs6kZspktV",
|
"id": "viwcpYeEpAs6kZspktV",
|
||||||
|
@ -62,7 +63,7 @@ FIELD_MAPPING = {
|
||||||
"airtable_column_type": None,
|
"airtable_column_type": None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
RAW_AIRTABLE_VIEW_DATA = {
|
RAW_AIRTABLE_GRID_VIEW_DATA = {
|
||||||
"id": "viwcpYeEpAs6kZspktV",
|
"id": "viwcpYeEpAs6kZspktV",
|
||||||
"frozenColumnCount": 1,
|
"frozenColumnCount": 1,
|
||||||
"columnOrder": [
|
"columnOrder": [
|
||||||
|
@ -85,6 +86,29 @@ RAW_AIRTABLE_VIEW_DATA = {
|
||||||
{"rowId": "rec2O9BdjKJO6dgj6QF", "visibility": True},
|
{"rowId": "rec2O9BdjKJO6dgj6QF", "visibility": True},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
RAW_AIRTABLE_GALLERY_VIEW_DATA = {
|
||||||
|
"id": "viwcpYeEpAs6kZspktV",
|
||||||
|
"frozenColumnCount": 1,
|
||||||
|
"columnOrder": [
|
||||||
|
{"columnId": "fldwSc9PqedIhTSqhi1", "visibility": True},
|
||||||
|
{"columnId": "fldwSc9PqedIhTSqhi2", "visibility": False},
|
||||||
|
],
|
||||||
|
"filters": None,
|
||||||
|
"lastSortsApplied": None,
|
||||||
|
"groupLevels": None,
|
||||||
|
"colorConfig": None,
|
||||||
|
"sharesById": {},
|
||||||
|
"metadata": {"gallery": {"coverColumnId": None, "coverFitType": "fit"}},
|
||||||
|
"description": None,
|
||||||
|
"createdByUserId": "usrdGm7k7NIVWhK7W7L",
|
||||||
|
"applicationTransactionNumber": 284,
|
||||||
|
"rowOrder": [
|
||||||
|
{"rowId": "recAAA5JwFXBk4swkfB", "visibility": True},
|
||||||
|
{"rowId": "rec9Imz1INvNXgRIXn1", "visibility": True},
|
||||||
|
{"rowId": "recyANUudYjDqIXdq9Z", "visibility": True},
|
||||||
|
{"rowId": "rec2O9BdjKJO6dgj6QF", "visibility": True},
|
||||||
|
],
|
||||||
|
}
|
||||||
RAW_VIEW_DATA_FILTERS = {
|
RAW_VIEW_DATA_FILTERS = {
|
||||||
"filterSet": [
|
"filterSet": [
|
||||||
{
|
{
|
||||||
|
@ -199,7 +223,7 @@ def test_import_grid_view():
|
||||||
ROW_ID_MAPPING,
|
ROW_ID_MAPPING,
|
||||||
RAW_AIRTABLE_TABLE,
|
RAW_AIRTABLE_TABLE,
|
||||||
RAW_AIRTABLE_VIEW,
|
RAW_AIRTABLE_VIEW,
|
||||||
RAW_AIRTABLE_VIEW_DATA,
|
RAW_AIRTABLE_GRID_VIEW_DATA,
|
||||||
AirtableImportConfig(),
|
AirtableImportConfig(),
|
||||||
AirtableImportReport(),
|
AirtableImportReport(),
|
||||||
)
|
)
|
||||||
|
@ -244,8 +268,67 @@ def test_import_grid_view():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_personal_view():
|
||||||
|
raw_airtable_table = deepcopy(RAW_AIRTABLE_TABLE)
|
||||||
|
raw_airtable_table["views"][0]["personalForUserId"] = "usr1234"
|
||||||
|
raw_airtable_view = raw_airtable_table["views"][0]
|
||||||
|
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
FIELD_MAPPING,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
RAW_AIRTABLE_GRID_VIEW_DATA,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(import_report.items) == 1
|
||||||
|
assert import_report.items[0].object_name == "Grid view"
|
||||||
|
assert import_report.items[0].scope == SCOPE_VIEW
|
||||||
|
assert import_report.items[0].table == "Data"
|
||||||
|
assert serialized_view["name"] == "Grid view (Personal)"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_locked_view():
|
||||||
|
raw_airtable_table = deepcopy(RAW_AIRTABLE_TABLE)
|
||||||
|
raw_airtable_table["views"][0]["lock"] = {
|
||||||
|
"lockLevelToEditViewName": "locked",
|
||||||
|
"lockLevelToEditViewDescription": "locked",
|
||||||
|
"lockLevelToEditViewLayout": "locked",
|
||||||
|
"lockLevelToEditViewConfig": "locked",
|
||||||
|
"lockLevelToCreateShareLink": "locked",
|
||||||
|
"lockLevelToDestroyView": "locked",
|
||||||
|
"allowFormSubmitterToIgnoreLockLevel": False,
|
||||||
|
"shouldWorkflowsRespectLockLevel": False,
|
||||||
|
"userId": "usripyu12348WK3n",
|
||||||
|
"description": None,
|
||||||
|
}
|
||||||
|
raw_airtable_view = raw_airtable_table["views"][0]
|
||||||
|
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
FIELD_MAPPING,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
RAW_AIRTABLE_GRID_VIEW_DATA,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(import_report.items) == 1
|
||||||
|
assert import_report.items[0].object_name == "Grid view"
|
||||||
|
assert import_report.items[0].scope == SCOPE_VIEW
|
||||||
|
assert import_report.items[0].table == "Data"
|
||||||
|
assert serialized_view["name"] == "Grid view"
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_xlarge_row_height():
|
def test_import_grid_view_xlarge_row_height():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
view_data["metadata"]["grid"]["rowHeight"] = "xlarge"
|
view_data["metadata"]["grid"]["rowHeight"] = "xlarge"
|
||||||
|
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
|
@ -263,7 +346,7 @@ def test_import_grid_view_xlarge_row_height():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_unknown_row_height():
|
def test_import_grid_view_unknown_row_height():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
view_data["metadata"]["grid"]["rowHeight"] = "unknown"
|
view_data["metadata"]["grid"]["rowHeight"] = "unknown"
|
||||||
|
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
|
@ -281,7 +364,7 @@ def test_import_grid_view_unknown_row_height():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_sorts():
|
def test_import_grid_view_sorts():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
view_data["lastSortsApplied"] = RAW_VIEW_DATA_SORTS
|
view_data["lastSortsApplied"] = RAW_VIEW_DATA_SORTS
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
@ -314,7 +397,7 @@ def test_import_grid_view_sorts():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_sort_field_not_found():
|
def test_import_grid_view_sort_field_not_found():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
view_data["lastSortsApplied"] = RAW_VIEW_DATA_SORTS
|
view_data["lastSortsApplied"] = RAW_VIEW_DATA_SORTS
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
import_report = AirtableImportReport()
|
import_report = AirtableImportReport()
|
||||||
|
@ -338,7 +421,7 @@ def test_import_grid_view_sort_field_not_found():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_sort_field_unsupported():
|
def test_import_grid_view_sort_field_unsupported():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
field_mapping["fldwSc9PqedIhTSqhi1"]["baserow_field_type"]._can_order_by_types = []
|
field_mapping["fldwSc9PqedIhTSqhi1"]["baserow_field_type"]._can_order_by_types = []
|
||||||
|
|
||||||
|
@ -365,7 +448,7 @@ def test_import_grid_view_sort_field_unsupported():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_group_bys():
|
def test_import_grid_view_group_bys():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
view_data["groupLevels"] = RAW_VIEW_DATA_GROUPS
|
view_data["groupLevels"] = RAW_VIEW_DATA_GROUPS
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
@ -398,7 +481,7 @@ def test_import_grid_view_group_bys():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_group_by_field_not_found():
|
def test_import_grid_view_group_by_field_not_found():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
view_data["groupLevels"] = RAW_VIEW_DATA_GROUPS
|
view_data["groupLevels"] = RAW_VIEW_DATA_GROUPS
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
import_report = AirtableImportReport()
|
import_report = AirtableImportReport()
|
||||||
|
@ -422,7 +505,7 @@ def test_import_grid_view_group_by_field_not_found():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_group_by_field_unsupported():
|
def test_import_grid_view_group_by_field_unsupported():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
field_mapping["fldwSc9PqedIhTSqhi1"]["baserow_field_type"]._can_group_by = False
|
field_mapping["fldwSc9PqedIhTSqhi1"]["baserow_field_type"]._can_group_by = False
|
||||||
|
|
||||||
|
@ -449,7 +532,7 @@ def test_import_grid_view_group_by_field_unsupported():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_group_by_order_unsupported():
|
def test_import_grid_view_group_by_order_unsupported():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
view_data["groupLevels"] = RAW_VIEW_DATA_GROUPS
|
view_data["groupLevels"] = RAW_VIEW_DATA_GROUPS
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
|
@ -476,7 +559,7 @@ def test_import_grid_view_group_by_order_unsupported():
|
||||||
|
|
||||||
|
|
||||||
def test_import_grid_view_field_order_and_visibility():
|
def test_import_grid_view_field_order_and_visibility():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
airtable_view_type = airtable_view_type_registry.get("grid")
|
airtable_view_type = airtable_view_type_registry.get("grid")
|
||||||
|
|
||||||
|
@ -515,7 +598,7 @@ def test_import_grid_view_field_order_and_visibility():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_import_grid_view_filters_and_groups():
|
def test_import_grid_view_filters_and_groups():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
for field_object in field_mapping.values():
|
for field_object in field_mapping.values():
|
||||||
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
||||||
|
@ -569,7 +652,7 @@ def test_import_grid_view_filters_and_groups():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_import_grid_view_empty_filters():
|
def test_import_grid_view_empty_filters():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
for field_object in field_mapping.values():
|
for field_object in field_mapping.values():
|
||||||
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
||||||
|
@ -598,7 +681,7 @@ def test_import_grid_view_empty_filters():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_import_grid_view_color_config_select_column_not_existing_column():
|
def test_import_grid_view_color_config_select_column_not_existing_column():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
for field_object in field_mapping.values():
|
for field_object in field_mapping.values():
|
||||||
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
||||||
|
@ -627,7 +710,7 @@ def test_import_grid_view_color_config_select_column_not_existing_column():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_import_grid_view_color_config_select_column():
|
def test_import_grid_view_color_config_select_column():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
for field_object in field_mapping.values():
|
for field_object in field_mapping.values():
|
||||||
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
||||||
|
@ -662,7 +745,7 @@ def test_import_grid_view_color_config_select_column():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_import_grid_view_color_config_color_definitions():
|
def test_import_grid_view_color_config_color_definitions():
|
||||||
view_data = deepcopy(RAW_AIRTABLE_VIEW_DATA)
|
view_data = deepcopy(RAW_AIRTABLE_GRID_VIEW_DATA)
|
||||||
field_mapping = deepcopy(FIELD_MAPPING)
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
for field_object in field_mapping.values():
|
for field_object in field_mapping.values():
|
||||||
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
field_object["baserow_field"].content_type = ContentType.objects.get_for_model(
|
||||||
|
@ -748,3 +831,200 @@ def test_import_grid_view_color_config_color_definitions():
|
||||||
"order": 1,
|
"order": 1,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_gallery_view():
|
||||||
|
view_data = deepcopy(RAW_AIRTABLE_GALLERY_VIEW_DATA)
|
||||||
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("gallery")
|
||||||
|
|
||||||
|
raw_airtable_view = deepcopy(RAW_AIRTABLE_VIEW)
|
||||||
|
raw_airtable_view["name"] = "Gallery view"
|
||||||
|
raw_airtable_view["type"] = "gallery"
|
||||||
|
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
field_mapping,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
RAW_AIRTABLE_TABLE,
|
||||||
|
raw_airtable_view,
|
||||||
|
view_data,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(import_report.items) == 0
|
||||||
|
assert serialized_view == {
|
||||||
|
"id": "viwcpYeEpAs6kZspktV",
|
||||||
|
"type": "gallery",
|
||||||
|
"name": "Gallery view",
|
||||||
|
"order": 1,
|
||||||
|
"ownership_type": "collaborative",
|
||||||
|
"owned_by": None,
|
||||||
|
"filter_type": "AND",
|
||||||
|
"filters_disabled": False,
|
||||||
|
"filters": [],
|
||||||
|
"filter_groups": [],
|
||||||
|
"sortings": [],
|
||||||
|
"decorations": [],
|
||||||
|
"public": False,
|
||||||
|
"field_options": [
|
||||||
|
{
|
||||||
|
"id": "viwcpYeEpAs6kZspktV_columnOrder_0",
|
||||||
|
"field_id": "fldwSc9PqedIhTSqhi1",
|
||||||
|
"hidden": False,
|
||||||
|
"order": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "viwcpYeEpAs6kZspktV_columnOrder_1",
|
||||||
|
"field_id": "fldwSc9PqedIhTSqhi2",
|
||||||
|
"hidden": True,
|
||||||
|
"order": 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_gallery_view_with_cover_column():
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("gallery")
|
||||||
|
|
||||||
|
view_data = deepcopy(RAW_AIRTABLE_GALLERY_VIEW_DATA)
|
||||||
|
view_data["metadata"]["gallery"]["coverColumnId"] = "fldwSc9PqedIhTSqhi3"
|
||||||
|
view_data["metadata"]["gallery"]["coverFitType"] = "crop"
|
||||||
|
|
||||||
|
raw_airtable_view = deepcopy(RAW_AIRTABLE_VIEW)
|
||||||
|
raw_airtable_view["name"] = "Gallery view"
|
||||||
|
raw_airtable_view["type"] = "gallery"
|
||||||
|
|
||||||
|
raw_airtable_table = deepcopy(RAW_AIRTABLE_TABLE)
|
||||||
|
raw_airtable_table["columns"].append(
|
||||||
|
{"id": "fldwSc9PqedIhTSqhi3", "name": "File", "type": "multipleAttachment"},
|
||||||
|
)
|
||||||
|
|
||||||
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
|
field_mapping["fldwSc9PqedIhTSqhi3"] = {
|
||||||
|
"baserow_field": FileField(
|
||||||
|
id="fldwSc9PqedIhTSqhi3", pk="fldwSc9PqedIhTSqhi3", name="File"
|
||||||
|
),
|
||||||
|
"baserow_field_type": FileFieldType(),
|
||||||
|
"raw_airtable_column": raw_airtable_table["columns"][2],
|
||||||
|
"airtable_column_type": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
field_mapping,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
view_data,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(import_report.items) == 0
|
||||||
|
assert serialized_view["card_cover_image_field_id"] == "fldwSc9PqedIhTSqhi3"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_gallery_view_with_unknown_cover_column():
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("gallery")
|
||||||
|
|
||||||
|
view_data = deepcopy(RAW_AIRTABLE_GALLERY_VIEW_DATA)
|
||||||
|
view_data["metadata"]["gallery"]["coverColumnId"] = "fldwSc9PqedIhTSqhi3"
|
||||||
|
|
||||||
|
raw_airtable_view = deepcopy(RAW_AIRTABLE_VIEW)
|
||||||
|
raw_airtable_view["name"] = "Gallery view"
|
||||||
|
raw_airtable_view["type"] = "gallery"
|
||||||
|
|
||||||
|
raw_airtable_table = deepcopy(RAW_AIRTABLE_TABLE)
|
||||||
|
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
FIELD_MAPPING,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
view_data,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "card_cover_image_field_id" not in serialized_view
|
||||||
|
assert len(import_report.items) == 1
|
||||||
|
assert import_report.items[0].object_name == "Gallery view"
|
||||||
|
assert import_report.items[0].scope == SCOPE_VIEW
|
||||||
|
assert import_report.items[0].table == "Data"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_gallery_view_with_incompatible_cover_column():
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("gallery")
|
||||||
|
|
||||||
|
view_data = deepcopy(RAW_AIRTABLE_GALLERY_VIEW_DATA)
|
||||||
|
view_data["metadata"]["gallery"]["coverColumnId"] = "fldwSc9PqedIhTSqhi2"
|
||||||
|
|
||||||
|
raw_airtable_view = deepcopy(RAW_AIRTABLE_VIEW)
|
||||||
|
raw_airtable_view["name"] = "Gallery view"
|
||||||
|
raw_airtable_view["type"] = "gallery"
|
||||||
|
|
||||||
|
raw_airtable_table = deepcopy(RAW_AIRTABLE_TABLE)
|
||||||
|
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
FIELD_MAPPING,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
view_data,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "card_cover_image_field_id" not in serialized_view
|
||||||
|
assert len(import_report.items) == 1
|
||||||
|
assert import_report.items[0].object_name == "Gallery view"
|
||||||
|
assert import_report.items[0].scope == SCOPE_VIEW
|
||||||
|
assert import_report.items[0].table == "Data"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_gallery_view_with_cover_column_type_fit():
|
||||||
|
airtable_view_type = airtable_view_type_registry.get("gallery")
|
||||||
|
|
||||||
|
view_data = deepcopy(RAW_AIRTABLE_GALLERY_VIEW_DATA)
|
||||||
|
view_data["metadata"]["gallery"]["coverColumnId"] = "fldwSc9PqedIhTSqhi3"
|
||||||
|
view_data["metadata"]["gallery"]["coverFitType"] = "fit"
|
||||||
|
|
||||||
|
raw_airtable_view = deepcopy(RAW_AIRTABLE_VIEW)
|
||||||
|
raw_airtable_view["name"] = "Gallery view"
|
||||||
|
raw_airtable_view["type"] = "gallery"
|
||||||
|
|
||||||
|
raw_airtable_table = deepcopy(RAW_AIRTABLE_TABLE)
|
||||||
|
raw_airtable_table["columns"].append(
|
||||||
|
{"id": "fldwSc9PqedIhTSqhi3", "name": "File", "type": "multipleAttachment"},
|
||||||
|
)
|
||||||
|
|
||||||
|
field_mapping = deepcopy(FIELD_MAPPING)
|
||||||
|
field_mapping["fldwSc9PqedIhTSqhi3"] = {
|
||||||
|
"baserow_field": FileField(
|
||||||
|
id="fldwSc9PqedIhTSqhi3", pk="fldwSc9PqedIhTSqhi3", name="File"
|
||||||
|
),
|
||||||
|
"baserow_field_type": FileFieldType(),
|
||||||
|
"raw_airtable_column": raw_airtable_table["columns"][2],
|
||||||
|
"airtable_column_type": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
import_report = AirtableImportReport()
|
||||||
|
serialized_view = airtable_view_type.to_serialized_baserow_view(
|
||||||
|
field_mapping,
|
||||||
|
ROW_ID_MAPPING,
|
||||||
|
raw_airtable_table,
|
||||||
|
raw_airtable_view,
|
||||||
|
view_data,
|
||||||
|
AirtableImportConfig(),
|
||||||
|
import_report,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(import_report.items) == 1
|
||||||
|
assert import_report.items[0].object_name == "Gallery view"
|
||||||
|
assert import_report.items[0].scope == SCOPE_VIEW
|
||||||
|
assert import_report.items[0].table == "Data"
|
||||||
|
assert serialized_view["card_cover_image_field_id"] == "fldwSc9PqedIhTSqhi3"
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"type": "feature",
|
||||||
|
"message": "Import Airtable gallery view.",
|
||||||
|
"domain": "database",
|
||||||
|
"issue_number": 793,
|
||||||
|
"bullet_points": [],
|
||||||
|
"created_at": "2025-03-17"
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue