From 8e273e696059c18e8fa17c11ad1237243f718c14 Mon Sep 17 00:00:00 2001
From: Jrmi <jrmi+gitlab@jeremiez.net>
Date: Sat, 30 Apr 2022 11:25:25 +0000
Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=88=203=EF=B8=8F=E2=83=A3=20-=20Row=20?=
 =?UTF-8?q?coloring=20v3=20-=20Add=20condition=20value=20provider?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../contrib/database/api/rows/schemas.py      |   20 +
 .../baserow/contrib/database/api/rows/urls.py |    7 +-
 .../contrib/database/api/rows/views.py        |  110 +-
 .../baserow/contrib/database/rows/handler.py  |   27 +-
 .../contrib/database/views/exceptions.py      |   11 +
 .../baserow/contrib/database/views/handler.py |    6 +
 .../contrib/database/views/registries.py      |   94 +-
 .../baserow/contrib/database/views/signals.py |   10 +
 .../database/api/rows/test_row_views.py       |  167 ++
 .../contrib/database/view/test_view_types.py  |   21 +-
 premium/backend/src/baserow_premium/apps.py   |   14 +-
 .../views/decorator_value_provider_types.py   |  159 ++
 .../views/test_premium_view_handler.py        |  149 +-
 .../views/test_premium_view_types.py          |   60 +
 .../assets/scss/components/all.scss           |    1 +
 ...conditional_color_value_provider_form.scss |   65 +
 .../ConditionalColorValueProviderForm.vue     |  206 +-
 .../SingleSelectColorValueProviderForm.vue    |    9 +-
 .../decoratorValueProviders.js                |   56 +
 .../modules/baserow_premium/locales/en.json   |    5 +
 .../core/assets/scss/components/filters.scss  |   49 +-
 .../modules/core/components/Picker.vue        |    2 +-
 .../modules/core/directives/sortable.js       |   14 +-
 .../components/field/FieldRatingSubForm.vue   |    2 +-
 .../components/view/ViewDecoratorContext.vue  |    7 +-
 .../view/ViewFieldConditionsForm.vue          |  255 +++
 .../components/view/ViewFilterForm.vue        |  219 +-
 .../components/view/ViewFilterTypeLinkRow.vue |   74 +-
 .../components/view/grid/GridView.vue         |    5 +
 .../components/view/grid/GridViewRow.vue      |    2 +-
 .../components/view/grid/GridViewRows.vue     |    7 +-
 .../components/view/grid/GridViewSection.vue  |    5 +
 web-frontend/modules/database/services/row.js |   43 +
 web-frontend/modules/database/store/view.js   |    8 +-
 web-frontend/package.json                     |    3 +-
 .../viewDecoratorContext.spec.js.snap         |   27 +-
 .../__snapshots__/viewFilterForm.spec.js.snap | 1934 ++++++++---------
 .../components/view/viewFilterForm.spec.js    |    2 +-
 38 files changed, 2518 insertions(+), 1337 deletions(-)
 create mode 100644 backend/src/baserow/contrib/database/api/rows/schemas.py
 create mode 100644 premium/backend/src/baserow_premium/views/decorator_value_provider_types.py
 create mode 100644 premium/web-frontend/modules/baserow_premium/assets/scss/components/views/conditional_color_value_provider_form.scss
 create mode 100644 web-frontend/modules/database/components/view/ViewFieldConditionsForm.vue

diff --git a/backend/src/baserow/contrib/database/api/rows/schemas.py b/backend/src/baserow/contrib/database/api/rows/schemas.py
new file mode 100644
index 000000000..07c08b2a9
--- /dev/null
+++ b/backend/src/baserow/contrib/database/api/rows/schemas.py
@@ -0,0 +1,20 @@
+from drf_spectacular.plumbing import build_object_type
+
+
+row_names_response_schema = build_object_type(
+    {
+        "{table_id}*": {
+            "type": "object",
+            "description": "An object containing the row names of table `table_id`.",
+            "properties": {
+                "{row_id}*": {
+                    "type": "string",
+                    "description": (
+                        "the name of the row with id `row_id` from table "
+                        "with id `table_id`."
+                    ),
+                }
+            },
+        },
+    },
+)
diff --git a/backend/src/baserow/contrib/database/api/rows/urls.py b/backend/src/baserow/contrib/database/api/rows/urls.py
index ee3720de8..47ab97130 100644
--- a/backend/src/baserow/contrib/database/api/rows/urls.py
+++ b/backend/src/baserow/contrib/database/api/rows/urls.py
@@ -1,6 +1,6 @@
 from django.urls import re_path
 
-from .views import RowsView, RowView, RowMoveView, BatchRowsView
+from .views import RowsView, RowView, RowMoveView, RowNamesView, BatchRowsView
 
 
 app_name = "baserow.contrib.database.api.rows"
@@ -22,4 +22,9 @@ urlpatterns = [
         RowMoveView.as_view(),
         name="move",
     ),
+    re_path(
+        r"names/$",
+        RowNamesView.as_view(),
+        name="names",
+    ),
 ]
diff --git a/backend/src/baserow/contrib/database/api/rows/views.py b/backend/src/baserow/contrib/database/api/rows/views.py
index ab2c3c836..8a6e46d09 100644
--- a/backend/src/baserow/contrib/database/api/rows/views.py
+++ b/backend/src/baserow/contrib/database/api/rows/views.py
@@ -10,7 +10,10 @@ from rest_framework.views import APIView
 
 from baserow.api.decorators import map_exceptions, validate_query_parameters
 from baserow.api.errors import ERROR_USER_NOT_IN_GROUP
-from baserow.api.exceptions import RequestBodyValidationException
+from baserow.api.exceptions import (
+    RequestBodyValidationException,
+    QueryParameterValidationException,
+)
 from baserow.api.pagination import PageNumberPagination
 from baserow.api.schemas import get_error_schema, CLIENT_SESSION_ID_SCHEMA_PARAMETER
 from baserow.api.trash.errors import ERROR_CANNOT_DELETE_ALREADY_DELETED_ITEM
@@ -56,6 +59,7 @@ from baserow.contrib.database.rows.exceptions import RowDoesNotExist, RowIdsNotU
 from baserow.contrib.database.rows.handler import RowHandler
 from baserow.contrib.database.table.exceptions import TableDoesNotExist
 from baserow.contrib.database.table.handler import TableHandler
+from baserow.contrib.database.table.models import Table
 from baserow.contrib.database.tokens.exceptions import NoPermissionToTable
 from baserow.contrib.database.tokens.handler import TokenHandler
 from baserow.contrib.database.views.exceptions import (
@@ -80,6 +84,7 @@ from baserow.contrib.database.fields.field_filters import (
     FILTER_TYPE_AND,
     FILTER_TYPE_OR,
 )
+from .schemas import row_names_response_schema
 
 
 class RowsView(APIView):
@@ -428,6 +433,109 @@ class RowsView(APIView):
         return Response(serializer.data)
 
 
+class RowNamesView(APIView):
+    authentication_classes = APIView.authentication_classes + [TokenAuthentication]
+    permission_classes = (IsAuthenticated,)
+
+    @extend_schema(
+        parameters=[
+            OpenApiParameter(
+                name="table__{id}",
+                location=OpenApiParameter.QUERY,
+                type=OpenApiTypes.STR,
+                description=(
+                    "A list of comma separated row ids to query from the table with "
+                    "id {id}. For example, if you "
+                    "want the name of row `42` and `43` from table `28` this parameter "
+                    "will be `table__28=42,43`. You can specify multiple rows for "
+                    "different tables but every tables must be in the same database. "
+                    "You need at least read permission on all specified tables."
+                ),
+            ),
+        ],
+        tags=["Database table rows"],
+        operation_id="list_database_table_row_names",
+        description=(
+            "Returns the names of the given row of the given tables. The name"
+            "of a row is the primary field value for this row. The result can be used"
+            "for example, when you want to display the name of a linked row from "
+            "another table."
+        ),
+        responses={
+            200: row_names_response_schema,
+            400: get_error_schema(
+                [
+                    "ERROR_USER_NOT_IN_GROUP",
+                ]
+            ),
+            401: get_error_schema(["ERROR_NO_PERMISSION_TO_TABLE"]),
+            404: get_error_schema(["ERROR_TABLE_DOES_NOT_EXIST"]),
+        },
+    )
+    @map_exceptions(
+        {
+            UserNotInGroup: ERROR_USER_NOT_IN_GROUP,
+            TableDoesNotExist: ERROR_TABLE_DOES_NOT_EXIST,
+            NoPermissionToTable: ERROR_NO_PERMISSION_TO_TABLE,
+        }
+    )
+    def get(self, request):
+        """
+        Returns the names (i.e. primary field value) of specified rows of given tables.
+        Can be used when you want to display a row name referenced from another table.
+        """
+
+        result = {}
+        database = None
+        table_handler = TableHandler()
+        token_handler = TokenHandler()
+        row_handler = RowHandler()
+
+        for name, value in request.GET.items():
+            if not name.startswith("table__"):
+                raise QueryParameterValidationException(
+                    detail='Only table Id prefixed by "table__" are allowed as parameter.',
+                    code="invalid_parameter",
+                )
+
+            try:
+                table_id = int(name[7:])
+            except ValueError:
+                raise QueryParameterValidationException(
+                    detail=(f'Failed to parse table id in "{name}".'),
+                    code="invalid_table_id",
+                )
+
+            try:
+                row_ids = [int(id) for id in value.split(",")]
+            except ValueError:
+                raise QueryParameterValidationException(
+                    detail=(
+                        f'Failed to parse row ids in "{value}" for '
+                        f'"table__{table_id}" parameter.'
+                    ),
+                    code="invalid_row_ids",
+                )
+
+            table_queryset = None
+            if database:
+                # Once we have the database, we want only tables from the same database
+                table_queryset = Table.objects.filter(database=database)
+
+            table = table_handler.get_table(table_id, base_queryset=table_queryset)
+
+            if not database:
+                # Check permission once
+                database = table.database
+                database.group.has_user(request.user, raise_error=True)
+
+            token_handler.check_table_permissions(request, "read", table, False)
+
+            result[table_id] = row_handler.get_row_names(table, row_ids)
+
+        return Response(result)
+
+
 class RowView(APIView):
     authentication_classes = APIView.authentication_classes + [TokenAuthentication]
     permission_classes = (IsAuthenticated,)
diff --git a/backend/src/baserow/contrib/database/rows/handler.py b/backend/src/baserow/contrib/database/rows/handler.py
index ae1b24a60..9ac3099d8 100644
--- a/backend/src/baserow/contrib/database/rows/handler.py
+++ b/backend/src/baserow/contrib/database/rows/handler.py
@@ -306,6 +306,31 @@ class RowHandler:
 
         return cast(GeneratedTableModelForUpdate, row)
 
+    def get_row_names(
+        self, table: "Table", row_ids: List[int], model: "GeneratedTableModel" = None
+    ) -> Dict[str, int]:
+        """
+        Returns the row names for all row ids specified in `row_ids` parameter from
+        the given table.
+
+        :param table: The table where the rows must be fetched from.
+        :param row_ids: The id of the rows that must be fetched.
+        :param model: If the correct model has already been generated it can be
+            provided so that it does not have to be generated for a second time.
+        :return: A dict of the requested rows names. The key are the row ids and the
+            values are the row names.
+        """
+
+        if not model:
+            primary_field = table.field_set.get(primary=True)
+            model = table.get_model(
+                field_ids=[], fields=[primary_field], add_dependencies=False
+            )
+
+        queryset = model.objects.filter(pk__in=row_ids)
+
+        return {row.id: str(row) for row in queryset}
+
     # noinspection PyMethodMayBeStatic
     def has_row(self, user, table, row_id, raise_error=False, model=None):
         """
@@ -313,7 +338,7 @@ class RowHandler:
 
         This method is preferred over using get_row when you do not actually need to
         access any values of the row as it will not construct a full model but instead
-        do a much more effecient query to check only if the row exists or not.
+        do a much more efficient query to check only if the row exists or not.
 
         :param user: The user of whose behalf the row is being checked.
         :type user: User
diff --git a/backend/src/baserow/contrib/database/views/exceptions.py b/backend/src/baserow/contrib/database/views/exceptions.py
index 269d54cf1..beb3954b6 100644
--- a/backend/src/baserow/contrib/database/views/exceptions.py
+++ b/backend/src/baserow/contrib/database/views/exceptions.py
@@ -101,6 +101,17 @@ class AggregationTypeAlreadyRegistered(Exception):
     """Raised when trying to register an aggregation type that exists already."""
 
 
+class DecoratorValueProviderTypeDoesNotExist(Exception):
+    """Raised when trying to get a decorator value provider type that does not exist."""
+
+
+class DecoratorValueProviderTypeAlreadyRegistered(Exception):
+    """
+    Raised when trying to register a decorator value provider type that exists
+    already.
+    """
+
+
 class GridViewAggregationDoesNotSupportField(Exception):
     """
     Raised when someone tries to use an aggregation type that doesn't support the
diff --git a/backend/src/baserow/contrib/database/views/handler.py b/backend/src/baserow/contrib/database/views/handler.py
index 212eb4872..7c1775b5a 100644
--- a/backend/src/baserow/contrib/database/views/handler.py
+++ b/backend/src/baserow/contrib/database/views/handler.py
@@ -51,6 +51,7 @@ from .registries import (
     view_type_registry,
     view_filter_type_registry,
     view_aggregation_type_registry,
+    decorator_value_provider_type_registry,
 )
 from .signals import (
     view_created,
@@ -359,6 +360,11 @@ class ViewHandler:
         for view_type in view_type_registry.get_all():
             view_type.after_field_type_change(field)
 
+        for (
+            decorator_value_provider_type
+        ) in decorator_value_provider_type_registry.get_all():
+            decorator_value_provider_type.after_field_type_change(field)
+
     def field_value_updated(self, updated_fields: Union[Iterable[Field], Field]):
         """
         Called after a field value has been modified because of a row creation,
diff --git a/backend/src/baserow/contrib/database/views/registries.py b/backend/src/baserow/contrib/database/views/registries.py
index 4979877e1..b77f147f5 100644
--- a/backend/src/baserow/contrib/database/views/registries.py
+++ b/backend/src/baserow/contrib/database/views/registries.py
@@ -1,4 +1,4 @@
-from typing import TYPE_CHECKING, Callable, Union, List, Iterable, Tuple
+from typing import TYPE_CHECKING, Callable, Union, List, Iterable, Tuple, Dict, Any
 
 from django.contrib.auth.models import User as DjangoUser
 from django.db import models as django_models
@@ -21,9 +21,6 @@ from baserow.core.registry import (
 )
 from baserow.contrib.database.fields import models as field_models
 
-if TYPE_CHECKING:
-    from baserow.contrib.database.views.models import View
-
 from .exceptions import (
     ViewTypeAlreadyRegistered,
     ViewTypeDoesNotExist,
@@ -31,8 +28,13 @@ from .exceptions import (
     ViewFilterTypeDoesNotExist,
     AggregationTypeDoesNotExist,
     AggregationTypeAlreadyRegistered,
+    DecoratorValueProviderTypeAlreadyRegistered,
+    DecoratorValueProviderTypeDoesNotExist,
 )
 
+if TYPE_CHECKING:
+    from baserow.contrib.database.views.models import View
+
 
 class ViewType(
     MapAPIExceptionsInstanceMixin,
@@ -285,30 +287,25 @@ class ViewType(
                 id_mapping["database_view_sortings"][view_sort_id] = view_sort_object.id
 
         if self.can_decorate:
-
-            def _update_field_id(node):
-                """Update field ids deeply inside a deep object."""
-
-                if isinstance(node, list):
-                    return [_update_field_id(subnode) for subnode in node]
-                if isinstance(node, dict):
-                    res = {}
-                    for key, value in node.items():
-                        if key in ["field_id", "field"] and isinstance(value, int):
-                            res[key] = id_mapping["database_fields"][value]
-                        else:
-                            res[key] = _update_field_id(value)
-                    return res
-                return node
-
             for view_decoration in decorations:
                 view_decoration_copy = view_decoration.copy()
                 view_decoration_id = view_decoration_copy.pop("id")
 
-                # Deeply update field ids to new one in value provider conf
-                view_decoration_copy["value_provider_conf"] = _update_field_id(
-                    view_decoration_copy["value_provider_conf"]
-                )
+                if view_decoration["value_provider_type"]:
+                    try:
+                        value_provider_type = (
+                            decorator_value_provider_type_registry.get(
+                                view_decoration["value_provider_type"]
+                            )
+                        )
+                    except DecoratorValueProviderTypeDoesNotExist:
+                        pass
+                    else:
+                        view_decoration_copy = (
+                            value_provider_type.set_import_serialized_value(
+                                view_decoration_copy, id_mapping
+                            )
+                        )
 
                 view_decoration_object = ViewDecoration.objects.create(
                     view=view, **view_decoration_copy
@@ -720,8 +717,57 @@ class ViewAggregationTypeRegistry(Registry):
     already_registered_exception_class = AggregationTypeAlreadyRegistered
 
 
+class DecoratorValueProviderType(Instance):
+    """
+    By declaring a new `DecoratorValueProviderType` you can define hooks on events that
+    can affect the decoration value provider configuration.
+    """
+
+    def set_import_serialized_value(
+        self, value: Dict[str, Any], id_mapping: Dict[str, Dict[int, Any]]
+    ) -> Dict[str, Any]:
+        """
+        This method is called before a decorator is imported. It can optionally be
+        modified. If the value_provider_conf for example points to a field or select
+        option id, it can be replaced with the correct value by doing a lookup in the
+        id_mapping.
+
+        :param value: The original exported value.
+        :param id_mapping: The map of exported ids to newly created ids that must be
+            updated when a new instance has been created.
+        :return: The new value that will be imported.
+        """
+
+    def after_field_delete(self, deleted_field: field_models.Field):
+        """
+        Triggered after a field has been deleted.
+        This hook gives the opportunity to react when a field is deleted.
+
+        :param deleted_field: the deleted field.
+        """
+
+    def after_field_type_change(self, field: field_models.Field):
+        """
+        This hook is called after the type of a field has changed and gives the
+        possibility to check compatibility or update configuration.
+
+        :param field: The concerned field.
+        """
+
+
+class DecoratorValueProviderTypeRegistry(Registry):
+    """
+    This registry contains declared decorator value provider if needed.
+    """
+
+    name = "decorator_value_provider_type"
+    does_not_exist_exception_class = DecoratorValueProviderTypeDoesNotExist
+    already_registered_exception_class = DecoratorValueProviderTypeAlreadyRegistered
+
+
 # A default view type registry is created here, this is the one that is used
 # throughout the whole Baserow application to add a new view type.
 view_type_registry = ViewTypeRegistry()
 view_filter_type_registry = ViewFilterTypeRegistry()
 view_aggregation_type_registry = ViewAggregationTypeRegistry()
+decorator_value_provider_type_registry = DecoratorValueProviderTypeRegistry()
diff --git a/backend/src/baserow/contrib/database/views/signals.py b/backend/src/baserow/contrib/database/views/signals.py
index 8a8ebd0a0..12ed3af89 100644
--- a/backend/src/baserow/contrib/database/views/signals.py
+++ b/backend/src/baserow/contrib/database/views/signals.py
@@ -32,3 +32,13 @@ def field_deleted(sender, field, **kwargs):
         GalleryView.objects.filter(card_cover_image_field_id=field.id).update(
             card_cover_image_field_id=None
         )
+
+    from baserow.contrib.database.views.registries import (
+        decorator_value_provider_type_registry,
+    )
+
+    # Call value provider type hooks
+    for (
+        decorator_value_provider_type
+    ) in decorator_value_provider_type_registry.get_all():
+        decorator_value_provider_type.after_field_delete(field)
diff --git a/backend/tests/baserow/contrib/database/api/rows/test_row_views.py b/backend/tests/baserow/contrib/database/api/rows/test_row_views.py
index 954cc809a..4f537b40d 100644
--- a/backend/tests/baserow/contrib/database/api/rows/test_row_views.py
+++ b/backend/tests/baserow/contrib/database/api/rows/test_row_views.py
@@ -1550,3 +1550,170 @@ def test_list_rows_returns_https_next_url(api_client, data_fixture, settings):
         response_json["next"] == "https://testserver:80/api/database/rows/table/"
         f"{table.id}/?page=2"
     )
+
+
+@pytest.mark.django_db
+def test_list_row_names(api_client, data_fixture):
+    user, jwt_token = data_fixture.create_user_and_token(
+        email="test@test.nl", password="password", first_name="Test1"
+    )
+    table = data_fixture.create_database_table(user=user)
+    data_fixture.create_text_field(name="Name", table=table, primary=True)
+
+    # A table for another user
+    table_off = data_fixture.create_database_table()
+
+    # A table in the same database
+    table_2 = data_fixture.create_database_table(user=user, database=table.database)
+    data_fixture.create_text_field(name="Name", table=table_2, primary=True)
+
+    # A table in another database
+    table_3 = data_fixture.create_database_table(user=user)
+    data_fixture.create_text_field(name="Name", table=table_3, primary=True)
+
+    token = TokenHandler().create_token(user, table.database.group, "Good")
+    wrong_token = TokenHandler().create_token(user, table.database.group, "Wrong")
+    TokenHandler().update_token_permissions(user, wrong_token, True, False, True, True)
+
+    model = table.get_model(attribute_names=True)
+    model.objects.create(name="Alpha")
+    model.objects.create(name="Beta")
+    model.objects.create(name="Gamma")
+    model.objects.create(name="Omega")
+
+    model_2 = table_2.get_model(attribute_names=True)
+    model_2.objects.create(name="Monday")
+    model_2.objects.create(name="Tuesday")
+
+    model_3 = table_3.get_model(attribute_names=True)
+    model_3.objects.create(name="January")
+
+    url = reverse("api:database:rows:names")
+    response = api_client.get(
+        f"{url}?table__99999=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_404_NOT_FOUND
+    assert response.json()["error"] == "ERROR_TABLE_DOES_NOT_EXIST"
+
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3&table__99999=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_404_NOT_FOUND
+    assert response.json()["error"] == "ERROR_TABLE_DOES_NOT_EXIST"
+
+    response = api_client.get(
+        f"{url}?table__{table_off.id}=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_400_BAD_REQUEST
+    assert response.json()["error"] == "ERROR_USER_NOT_IN_GROUP"
+
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION="Token abc123",
+    )
+    assert response.status_code == HTTP_401_UNAUTHORIZED
+    assert response.json()["error"] == "ERROR_TOKEN_DOES_NOT_EXIST"
+
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"Token {wrong_token.key}",
+    )
+    assert response.status_code == HTTP_401_UNAUTHORIZED
+    assert response.json()["error"] == "ERROR_NO_PERMISSION_TO_TABLE"
+
+    user.is_active = False
+    user.save()
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"Token {token.key}",
+    )
+    assert response.status_code == HTTP_401_UNAUTHORIZED
+    assert response.json()["error"] == "ERROR_USER_NOT_ACTIVE"
+    user.is_active = True
+    user.save()
+
+    response = api_client.get(
+        f"{url}?tabble__{table.id}=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_400_BAD_REQUEST
+    response_json = response.json()
+    assert response.json()["error"] == "ERROR_QUERY_PARAMETER_VALIDATION"
+    assert (
+        response.json()["detail"]
+        == 'Only table Id prefixed by "table__" are allowed as parameter.'
+    )
+
+    response = api_client.get(
+        f"{url}?table__12i=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_400_BAD_REQUEST
+    response_json = response.json()
+    assert response.json()["error"] == "ERROR_QUERY_PARAMETER_VALIDATION"
+    assert response.json()["detail"] == 'Failed to parse table id in "table__12i".'
+
+    response = api_client.get(
+        f"{url}?table__23=1p,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_400_BAD_REQUEST
+    response_json = response.json()
+    assert response.json()["error"] == "ERROR_QUERY_PARAMETER_VALIDATION"
+    assert (
+        response.json()["detail"]
+        == 'Failed to parse row ids in "1p,2,3" for "table__23" parameter.'
+    )
+
+    response = api_client.get(
+        f"{url}?table__{table.id}=1",
+        format="json",
+        HTTP_AUTHORIZATION=f"Token {token.key}",
+    )
+    assert response.status_code == HTTP_200_OK
+
+    # One query one table
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_200_OK
+    response_json = response.json()
+
+    assert response_json == {str(table.id): {"1": "Alpha", "2": "Beta", "3": "Gamma"}}
+
+    # 2 tables, one database
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3&table__{table_2.id}=1,2",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_200_OK
+    response_json = response.json()
+
+    assert response_json == {
+        str(table.id): {"1": "Alpha", "2": "Beta", "3": "Gamma"},
+        str(table_2.id): {"1": "Monday", "2": "Tuesday"},
+    }
+
+    # Two tables, two databases
+    response = api_client.get(
+        f"{url}?table__{table.id}=1,2,3&table__{table_3.id}=1",
+        format="json",
+        HTTP_AUTHORIZATION=f"JWT {jwt_token}",
+    )
+    assert response.status_code == HTTP_404_NOT_FOUND
+    assert response.json()["error"] == "ERROR_TABLE_DOES_NOT_EXIST"
diff --git a/backend/tests/baserow/contrib/database/view/test_view_types.py b/backend/tests/baserow/contrib/database/view/test_view_types.py
index d0bf671ff..43f39ec18 100644
--- a/backend/tests/baserow/contrib/database/view/test_view_types.py
+++ b/backend/tests/baserow/contrib/database/view/test_view_types.py
@@ -36,14 +36,7 @@ def test_import_export_grid_view(data_fixture):
 
     view_decoration = data_fixture.create_view_decoration(
         view=grid_view,
-        value_provider_conf={
-            "field_id": field.id,
-            "other": [
-                {"field": field.id, "other": 1},
-                {"answer": 42, "field_id": field.id},
-                {"field": {"non_int": True}},
-            ],
-        },
+        value_provider_conf={"config": 12},
     )
 
     id_mapping = {"database_fields": {field.id: imported_field.id}}
@@ -80,14 +73,10 @@ def test_import_export_grid_view(data_fixture):
         view_decoration.value_provider_type
         == imported_view_decoration.value_provider_type
     )
-    assert imported_view_decoration.value_provider_conf == {
-        "field_id": imported_field.id,
-        "other": [
-            {"field": imported_field.id, "other": 1},
-            {"answer": 42, "field_id": imported_field.id},
-            {"field": {"non_int": True}},
-        ],
-    }
+    assert (
+        imported_view_decoration.value_provider_conf
+        == imported_view_decoration.value_provider_conf
+    )
     assert view_decoration.order == imported_view_decoration.order
 
     imported_field_options = imported_grid_view.get_field_options()
diff --git a/premium/backend/src/baserow_premium/apps.py b/premium/backend/src/baserow_premium/apps.py
index 5a009e560..9919fb091 100644
--- a/premium/backend/src/baserow_premium/apps.py
+++ b/premium/backend/src/baserow_premium/apps.py
@@ -9,7 +9,10 @@ class BaserowPremiumConfig(AppConfig):
         from baserow.api.user.registries import user_data_registry
         from baserow.contrib.database.export.registries import table_exporter_registry
         from baserow.contrib.database.rows.registries import row_metadata_registry
-        from baserow.contrib.database.views.registries import view_type_registry
+        from baserow.contrib.database.views.registries import (
+            view_type_registry,
+            decorator_value_provider_type_registry,
+        )
 
         from baserow_premium.row_comments.row_metadata_types import (
             RowCommentCountMetadataType,
@@ -22,6 +25,10 @@ class BaserowPremiumConfig(AppConfig):
         from .plugins import PremiumPlugin
         from .export.exporter_types import JSONTableExporter, XMLTableExporter
         from .views.view_types import KanbanViewType
+        from .views.decorator_value_provider_types import (
+            ConditionalColorValueProviderType,
+            SelectColorValueProviderType,
+        )
 
         plugin_registry.register(PremiumPlugin())
 
@@ -34,6 +41,11 @@ class BaserowPremiumConfig(AppConfig):
 
         view_type_registry.register(KanbanViewType())
 
+        decorator_value_provider_type_registry.register(
+            ConditionalColorValueProviderType()
+        )
+        decorator_value_provider_type_registry.register(SelectColorValueProviderType())
+
         # The signals must always be imported last because they use the registries
         # which need to be filled first.
         import baserow_premium.ws.signals  # noqa: F403, F401
diff --git a/premium/backend/src/baserow_premium/views/decorator_value_provider_types.py b/premium/backend/src/baserow_premium/views/decorator_value_provider_types.py
new file mode 100644
index 000000000..aff63a264
--- /dev/null
+++ b/premium/backend/src/baserow_premium/views/decorator_value_provider_types.py
@@ -0,0 +1,159 @@
+from baserow.contrib.database.fields.field_types import (
+    SingleSelectFieldType,
+)
+
+from baserow.contrib.database.views.models import ViewDecoration
+from baserow.contrib.database.views.handler import ViewHandler
+from baserow.contrib.database.views.registries import (
+    DecoratorValueProviderType,
+    view_filter_type_registry,
+)
+
+
+class SelectColorValueProviderType(DecoratorValueProviderType):
+    type = "single_select_color"
+
+    def set_import_serialized_value(self, value, id_mapping) -> str:
+        """
+        Update the field id with the newly created one.
+        """
+        old_field_id = value["value_provider_conf"].get("field_id", None)
+
+        if old_field_id:
+            value["value_provider_conf"]["field_id"] = id_mapping[
+                "database_fields"
+            ].get(old_field_id, None)
+
+        return value
+
+    def after_field_delete(self, deleted_field):
+        """
+        Remove the field from the value_provider_conf filters if necessary.
+        """
+
+        view_handler = ViewHandler()
+
+        queryset = ViewDecoration.objects.filter(
+            view__table=deleted_field.table,
+            value_provider_type=SelectColorValueProviderType.type,
+            value_provider_conf__field_id=deleted_field.id,
+        )
+
+        for decoration in queryset.all():
+            new_conf = {**decoration.value_provider_conf}
+            new_conf["field_id"] = None
+            view_handler.update_decoration(decoration, value_provider_conf=new_conf)
+
+    def after_field_type_change(self, field):
+        """
+        Unset the field if the type is not a select anymore.
+        """
+
+        from baserow.contrib.database.fields.registries import field_type_registry
+
+        field_type = field_type_registry.get_by_model(field.specific_class)
+
+        view_handler = ViewHandler()
+
+        if field_type.type != SingleSelectFieldType.type:
+
+            queryset = ViewDecoration.objects.filter(
+                view__table=field.table,
+                value_provider_type=SelectColorValueProviderType.type,
+                value_provider_conf__field_id=field.id,
+            )
+
+            for decoration in queryset.all():
+                new_conf = {**decoration.value_provider_conf}
+                new_conf["field_id"] = None
+                view_handler.update_decoration(decoration, value_provider_conf=new_conf)
+
+
+class ConditionalColorValueProviderType(DecoratorValueProviderType):
+    type = "conditional_color"
+
+    def set_import_serialized_value(self, value, id_mapping) -> str:
+        """
+        Update the field ids of each filter with the newly created one.
+        """
+
+        value_provider_conf = value["value_provider_conf"]
+
+        for color in value_provider_conf["colors"]:
+            for filter in color["filters"]:
+                new_field_id = id_mapping["database_fields"][filter["field"]]
+                filter["field"] = new_field_id
+
+        return value
+
+    def _map_filter_from_config(self, conf, fn):
+        """
+        Map a function on each filters of the configuration. If the given function
+        returns None, the filter is removed from the list of filters.
+        """
+
+        modified = False
+        for color in conf["colors"]:
+            new_filters = []
+            for filter in color["filters"]:
+                new_filter = fn(filter)
+                modified = modified or new_filter != filter
+                if new_filter is not None:
+                    new_filters.append(new_filter)
+
+            modified = modified or len(new_filters) != len(color["filters"])
+            color["filters"] = new_filters
+
+        return conf, modified
+
+    def after_field_delete(self, deleted_field):
+        """
+        Remove the field from the value_provider_conf filters if necessary.
+        """
+
+        # We can't filter with the JSON field here as we have nested lists
+        queryset = ViewDecoration.objects.filter(
+            view__table=deleted_field.table,
+            value_provider_type=ConditionalColorValueProviderType.type,
+        )
+
+        view_handler = ViewHandler()
+
+        for decoration in queryset.all():
+            new_conf, modified = self._map_filter_from_config(
+                decoration.value_provider_conf,
+                lambda f: None if f["field"] == deleted_field.id else f,
+            )
+            if modified:
+                view_handler.update_decoration(decoration, value_provider_conf=new_conf)
+
+    def after_field_type_change(self, field):
+        """
+        Remove filters type that are not compatible anymore from configuration
+        """
+
+        queryset = ViewDecoration.objects.filter(
+            view__table=field.table,
+            value_provider_type=ConditionalColorValueProviderType.type,
+        )
+
+        view_handler = ViewHandler()
+
+        def compatible_filter_only(filter):
+            if filter["field"] != field.id:
+                return filter
+
+            filter_type = view_filter_type_registry.get(filter["type"])
+            if not filter_type.field_is_compatible(field):
+                return None
+            return filter
+
+        for decoration in queryset.all():
+            # Check which filters are not compatible anymore and remove those.
+            new_conf, modified = self._map_filter_from_config(
+                decoration.value_provider_conf,
+                compatible_filter_only,
+            )
+
+            if modified:
+                view_handler.update_decoration(decoration, value_provider_conf=new_conf)
diff --git a/premium/backend/tests/baserow_premium/views/test_premium_view_handler.py b/premium/backend/tests/baserow_premium/views/test_premium_view_handler.py
index 5e59b61a9..148933a0d 100644
--- a/premium/backend/tests/baserow_premium/views/test_premium_view_handler.py
+++ b/premium/backend/tests/baserow_premium/views/test_premium_view_handler.py
@@ -1,7 +1,8 @@
 import pytest
 
-from baserow.contrib.database.views.models import View
+from baserow.contrib.database.views.models import View, ViewDecoration
 from baserow_premium.views.handler import get_rows_grouped_by_single_select_field
+from baserow.contrib.database.fields.handler import FieldHandler
 
 
 @pytest.mark.django_db
@@ -232,3 +233,149 @@ def test_get_rows_grouped_by_single_select_field_with_empty_table(
     assert len(rows) == 1
     assert rows["null"]["count"] == 0
     assert len(rows["null"]["results"]) == 0
+
+
+@pytest.mark.django_db
+def test_field_type_changed_w_decoration(data_fixture):
+    user = data_fixture.create_user()
+    table = data_fixture.create_database_table(user=user)
+    text_field = data_fixture.create_text_field(table=table)
+    option_field = data_fixture.create_single_select_field(
+        table=table, name="option_field", order=1
+    )
+    option_a = data_fixture.create_select_option(
+        field=option_field, value="A", color="blue"
+    )
+
+    grid_view = data_fixture.create_grid_view(table=table)
+
+    select_view_decoration = data_fixture.create_view_decoration(
+        view=grid_view,
+        value_provider_type="single_select_color",
+        value_provider_conf={"field_id": option_field.id},
+        order=1,
+    )
+
+    condition_view_decoration = data_fixture.create_view_decoration(
+        view=grid_view,
+        value_provider_type="conditional_color",
+        value_provider_conf={
+            "colors": [
+                {"filters": [{"field": text_field.id, "type": "equal"}]},
+                {"filters": [{"field": option_field.id, "type": "equal"}]},
+                {
+                    "filters": [
+                        {"field": option_field.id, "type": "single_select_equal"}
+                    ]
+                },
+                {"filters": []},
+            ]
+        },
+        order=2,
+    )
+
+    field_handler = FieldHandler()
+
+    decorations = list(ViewDecoration.objects.all())
+    assert len(decorations) == 2
+    assert (
+        decorations[0].value_provider_conf == select_view_decoration.value_provider_conf
+    )
+    assert (
+        decorations[1].value_provider_conf
+        == condition_view_decoration.value_provider_conf
+    )
+
+    field_handler.update_field(
+        user=user, field=option_field, new_type_name="single_select"
+    )
+
+    decorations = list(ViewDecoration.objects.all())
+    assert (
+        decorations[0].value_provider_conf == select_view_decoration.value_provider_conf
+    )
+    assert (
+        decorations[1].value_provider_conf
+        == condition_view_decoration.value_provider_conf
+    )
+
+    field_handler.update_field(user=user, field=option_field, new_type_name="text")
+
+    decorations = list(ViewDecoration.objects.all())
+    assert decorations[0].value_provider_conf == {"field_id": None}
+    assert decorations[1].value_provider_conf == {
+        "colors": [
+            {"filters": [{"type": "equal", "field": text_field.id}]},
+            {"filters": [{"type": "equal", "field": option_field.id}]},
+            {"filters": []},
+            {"filters": []},
+        ]
+    }
+
+
+@pytest.mark.django_db
+def test_field_deleted_w_decoration(data_fixture):
+    user = data_fixture.create_user()
+    table = data_fixture.create_database_table(user=user)
+    text_field = data_fixture.create_text_field(table=table)
+    option_field = data_fixture.create_single_select_field(
+        table=table, name="option_field", order=1
+    )
+    option_a = data_fixture.create_select_option(
+        field=option_field, value="A", color="blue"
+    )
+
+    grid_view = data_fixture.create_grid_view(table=table)
+
+    select_view_decoration = data_fixture.create_view_decoration(
+        view=grid_view,
+        value_provider_type="single_select_color",
+        value_provider_conf={"field_id": option_field.id},
+        order=1,
+    )
+
+    condition_view_decoration = data_fixture.create_view_decoration(
+        view=grid_view,
+        value_provider_type="conditional_color",
+        value_provider_conf={
+            "colors": [
+                {"filters": [{"field": text_field.id, "type": "equal"}]},
+                {"filters": [{"field": option_field.id, "type": "equal"}]},
+                {
+                    "filters": [
+                        {"field": option_field.id, "type": "single_select_equal"}
+                    ]
+                },
+                {"filters": []},
+            ]
+        },
+        order=2,
+    )
+
+    field_handler = FieldHandler()
+
+    field_handler.delete_field(user=user, field=option_field)
+
+    decorations = list(ViewDecoration.objects.all())
+    assert decorations[0].value_provider_conf == {"field_id": None}
+    assert decorations[1].value_provider_conf == {
+        "colors": [
+            {"filters": [{"type": "equal", "field": text_field.id}]},
+            {"filters": []},
+            {"filters": []},
+            {"filters": []},
+        ]
+    }
+
+    field_handler.delete_field(user=user, field=text_field)
+
+    decorations = list(ViewDecoration.objects.all())
+    assert decorations[0].value_provider_conf == {"field_id": None}
+    assert decorations[1].value_provider_conf == {
+        "colors": [
+            {"filters": []},
+            {"filters": []},
+            {"filters": []},
+            {"filters": []},
+        ]
+    }
diff --git a/premium/backend/tests/baserow_premium/views/test_premium_view_types.py b/premium/backend/tests/baserow_premium/views/test_premium_view_types.py
index b8202b49f..d86117b8a 100644
--- a/premium/backend/tests/baserow_premium/views/test_premium_view_types.py
+++ b/premium/backend/tests/baserow_premium/views/test_premium_view_types.py
@@ -130,6 +130,66 @@ def test_import_export_kanban_view(premium_data_fixture, tmpdir):
     assert field_option.order == imported_field_option.order
 
 
+@pytest.mark.django_db
+def test_import_export_grid_view_w_decorator(data_fixture):
+    grid_view = data_fixture.create_grid_view(
+        name="Test", order=1, filter_type="AND", filters_disabled=False
+    )
+    field = data_fixture.create_text_field(table=grid_view.table)
+    imported_field = data_fixture.create_text_field(table=grid_view.table)
+
+    view_decoration = data_fixture.create_view_decoration(
+        view=grid_view,
+        value_provider_type="single_select_color",
+        value_provider_conf={"field_id": field.id},
+        order=1,
+    )
+
+    view_decoration_2 = data_fixture.create_view_decoration(
+        view=grid_view,
+        value_provider_type="conditional_color",
+        value_provider_conf={
+            "colors": [
+                {"filters": [{"field": field.id}]},
+                {"filters": [{"field": field.id}]},
+            ]
+        },
+        order=2,
+    )
+
+    id_mapping = {"database_fields": {field.id: imported_field.id}}
+
+    grid_view_type = view_type_registry.get("grid")
+    serialized = grid_view_type.export_serialized(grid_view, None, None)
+    imported_grid_view = grid_view_type.import_serialized(
+        grid_view.table, serialized, id_mapping, None, None
+    )
+
+    imported_view_decorations = imported_grid_view.viewdecoration_set.all()
+    assert view_decoration.id != imported_view_decorations[0].id
+    assert view_decoration.type == imported_view_decorations[0].type
+    assert (
+        view_decoration.value_provider_type
+        == imported_view_decorations[0].value_provider_type
+    )
+    assert imported_view_decorations[0].value_provider_conf == {
+        "field_id": imported_field.id
+    }
+
+    assert view_decoration_2.id != imported_view_decorations[1].id
+    assert view_decoration_2.type == imported_view_decorations[1].type
+    assert (
+        view_decoration_2.value_provider_type
+        == imported_view_decorations[1].value_provider_type
+    )
+    assert imported_view_decorations[1].value_provider_conf == {
+        "colors": [
+            {"filters": [{"field": imported_field.id}]},
+            {"filters": [{"field": imported_field.id}]},
+        ]
+    }
+
+
 @pytest.mark.django_db
 def test_newly_created_view(premium_data_fixture):
     user = premium_data_fixture.create_user(has_active_premium_license=True)
diff --git a/premium/web-frontend/modules/baserow_premium/assets/scss/components/all.scss b/premium/web-frontend/modules/baserow_premium/assets/scss/components/all.scss
index c33b828b2..9b3f804af 100644
--- a/premium/web-frontend/modules/baserow_premium/assets/scss/components/all.scss
+++ b/premium/web-frontend/modules/baserow_premium/assets/scss/components/all.scss
@@ -9,3 +9,4 @@
 @import 'views/kanban';
 @import 'views/decorators';
 @import 'impersonate_warning';
+@import 'views/conditional_color_value_provider_form';
diff --git a/premium/web-frontend/modules/baserow_premium/assets/scss/components/views/conditional_color_value_provider_form.scss b/premium/web-frontend/modules/baserow_premium/assets/scss/components/views/conditional_color_value_provider_form.scss
new file mode 100644
index 000000000..cc0f3f16f
--- /dev/null
+++ b/premium/web-frontend/modules/baserow_premium/assets/scss/components/views/conditional_color_value_provider_form.scss
@@ -0,0 +1,65 @@
+.conditional-color-value-provider-form__color {
+  background-color: $color-neutral-100;
+  padding: 12px 30px;
+  margin: 0 -20px;
+  margin-bottom: 12px;
+
+  & .filters__item {
+    margin-left: 1px;
+  }
+}
+
+.conditional-color-value-provider-form__color-header {
+  display: flex;
+  justify-content: left;
+  align-items: center;
+}
+
+.conditional-color-value-provider-form__color-handle {
+  width: 12px;
+  height: 24px;
+  background-image: radial-gradient($color-neutral-200 40%, transparent 40%);
+  background-size: 4px 4px;
+  background-repeat: repeat;
+  margin-right: 12px;
+  cursor: grab;
+}
+
+.conditional-color-value-provider-form__color-trash-link {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: $color-primary-900;
+  padding: 6px;
+  border-radius: 4px;
+  margin-left: 4px;
+
+  &:hover {
+    text-decoration: none;
+    background-color: $color-neutral-100;
+  }
+}
+
+.conditional-color-value-provider-form__color-color {
+  @extend %option-shadow;
+
+  padding: 6px 9px;
+  text-align: center;
+  color: $color-primary-900;
+  border-radius: 3px;
+  font-size: 14px;
+}
+
+.conditional-color-value-provider-form__color-filter--empty {
+  padding: 12px;
+  white-space: normal;
+  text-align: center;
+}
+
+.conditional-color-value-provider-form__color-filters {
+  margin-bottom: 12px;
+}
+
+.conditional-color-value-provider-form__color-filter-add {
+  color: $color-primary-900;
+}
diff --git a/premium/web-frontend/modules/baserow_premium/components/views/ConditionalColorValueProviderForm.vue b/premium/web-frontend/modules/baserow_premium/components/views/ConditionalColorValueProviderForm.vue
index ae5fc1ada..6c8cbd246 100644
--- a/premium/web-frontend/modules/baserow_premium/components/views/ConditionalColorValueProviderForm.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/views/ConditionalColorValueProviderForm.vue
@@ -1,11 +1,87 @@
 <template>
-  <div class="margin-bottom-2">Not available yet!</div>
+  <div>
+    <div>
+      <div
+        v-for="color in options.colors || []"
+        :key="color.uid"
+        v-sortable="{
+          id: color.uid,
+          update: orderColor,
+          handle: '[data-sortable-handle]',
+          marginTop: -5,
+        }"
+        class="conditional-color-value-provider-form__color"
+      >
+        <div class="conditional-color-value-provider-form__color-header">
+          <div
+            class="conditional-color-value-provider-form__color-handle"
+            data-sortable-handle
+          />
+          <a
+            :ref="`colorSelect-${color.uid}`"
+            class="conditional-color-value-provider-form__color-color"
+            :class="`background-color--${color.color}`"
+            @click="openColor(color)"
+          >
+            <i class="fas fa-caret-down"></i>
+          </a>
+          <div :style="{ flex: 1 }" />
+          <a
+            v-if="options.colors.length > 1"
+            class="conditional-color-value-provider-form__color-trash-link"
+            @click="deleteColor(color)"
+          >
+            <i class="fa fa-trash" />
+          </a>
+        </div>
+        <div
+          v-if="color.filters.length === 0"
+          class="conditional-color-value-provider-form__color-filter--empty"
+        >
+          {{ $t('conditionalColorValueProviderForm.colorAlwaysApply') }}
+        </div>
+        <ViewFieldConditionsForm
+          v-show="color.filters.length !== 0"
+          class="conditional-color-value-provider-form__color-filters"
+          :filters="color.filters"
+          :disable-filter="false"
+          :filter-type="color.operator"
+          :primary="primary"
+          :fields="fields"
+          :view="view"
+          :read-only="readOnly"
+          @deleteFilter="deleteFilter(color, $event)"
+          @updateFilter="updateFilter(color, $event)"
+          @selectOperator="updateColor(color, { operator: $event })"
+        />
+        <a
+          class="conditional-color-value-provider-form__color-filter-add"
+          @click.prevent="addFilter(color)"
+        >
+          <i class="fas fa-plus"></i>
+          {{ $t('conditionalColorValueProviderForm.addCondition') }}</a
+        >
+        <ColorSelectContext
+          :ref="`colorContext-${color.uid}`"
+          @selected="updateColor(color, { color: $event })"
+        ></ColorSelectContext>
+      </div>
+    </div>
+    <a class="colors__add" @click.prevent="addColor()">
+      <i class="fas fa-plus"></i>
+      {{ $t('conditionalColorValueProviderForm.addColor') }}</a
+    >
+  </div>
 </template>
 
 <script>
+import ViewFieldConditionsForm from '@baserow/modules/database/components/view/ViewFieldConditionsForm'
+import ColorSelectContext from '@baserow/modules/core/components/ColorSelectContext'
+import { ConditionalColorValueProviderType } from '@baserow_premium/decoratorValueProviders'
+
 export default {
   name: 'ConditionalColorValueProvider',
-  components: {},
+  components: { ViewFieldConditionsForm, ColorSelectContext },
   props: {
     options: {
       type: Object,
@@ -19,6 +95,10 @@ export default {
       type: Object,
       required: true,
     },
+    primary: {
+      type: Object,
+      required: true,
+    },
     fields: {
       type: Array,
       required: true,
@@ -28,6 +108,126 @@ export default {
       required: true,
     },
   },
-  computed: {},
+  computed: {
+    allFields() {
+      return [this.primary, ...this.fields]
+    },
+  },
+  methods: {
+    orderColor(colorIds) {
+      const newColors = colorIds.map((colorId) =>
+        this.options.colors.find(({ uid }) => uid === colorId)
+      )
+      this.$emit('update', {
+        colors: newColors,
+      })
+    },
+    openColor(color) {
+      this.$refs[`colorContext-${color.uid}`][0].setActive(color.color)
+      this.$refs[`colorContext-${color.uid}`][0].toggle(
+        this.$refs[`colorSelect-${color.uid}`][0],
+        'bottom',
+        'left',
+        4
+      )
+    },
+    addColor() {
+      this.$emit('update', {
+        colors: [
+          ...this.options.colors,
+          ConditionalColorValueProviderType.getDefaultColorConf(
+            this.$registry,
+            {
+              fields: this.allFields,
+            },
+            true
+          ),
+        ],
+      })
+    },
+    updateColor(color, values) {
+      const newColors = this.options.colors.map((colorConf) => {
+        if (colorConf.uid === color.uid) {
+          return { ...colorConf, ...values }
+        }
+        return colorConf
+      })
+
+      this.$emit('update', {
+        colors: newColors,
+      })
+    },
+    deleteColor(color) {
+      const newColors = this.options.colors.filter(({ uid }) => {
+        return uid !== color.uid
+      })
+
+      this.$emit('update', {
+        colors: newColors,
+      })
+    },
+    addFilter(color) {
+      const newColors = this.options.colors.map((colorConf) => {
+        if (colorConf.uid === color.uid) {
+          return {
+            ...colorConf,
+            filters: [
+              ...colorConf.filters,
+              ConditionalColorValueProviderType.getDefaultFilterConf(
+                this.$registry,
+                {
+                  fields: this.allFields,
+                }
+              ),
+            ],
+          }
+        }
+        return colorConf
+      })
+
+      this.$emit('update', {
+        colors: newColors,
+      })
+    },
+    updateFilter(color, { filter, values }) {
+      const newColors = this.options.colors.map((colorConf) => {
+        if (colorConf.uid === color.uid) {
+          const newFilters = colorConf.filters.map((filterConf) => {
+            if (filterConf.id === filter.id) {
+              return { ...filter, ...values }
+            }
+            return filterConf
+          })
+          return {
+            ...colorConf,
+            filters: newFilters,
+          }
+        }
+        return colorConf
+      })
+
+      this.$emit('update', {
+        colors: newColors,
+      })
+    },
+    deleteFilter(color, filter) {
+      const newColors = this.options.colors.map((colorConf) => {
+        if (colorConf.uid === color.uid) {
+          const newFilters = colorConf.filters.filter((filterConf) => {
+            return filterConf.id !== filter.id
+          })
+          return {
+            ...colorConf,
+            filters: newFilters,
+          }
+        }
+        return colorConf
+      })
+
+      this.$emit('update', {
+        colors: newColors,
+      })
+    },
+  },
 }
 </script>
diff --git a/premium/web-frontend/modules/baserow_premium/components/views/SingleSelectColorValueProviderForm.vue b/premium/web-frontend/modules/baserow_premium/components/views/SingleSelectColorValueProviderForm.vue
index 4a41e0ee7..961a81a90 100644
--- a/premium/web-frontend/modules/baserow_premium/components/views/SingleSelectColorValueProviderForm.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/views/SingleSelectColorValueProviderForm.vue
@@ -15,6 +15,7 @@
 
 <script>
 import ChooseSingleSelectField from '@baserow/modules/database/components/field/ChooseSingleSelectField.vue'
+import { SingleSelectFieldType } from '@baserow/modules/database/fieldTypes'
 
 export default {
   name: 'SingleSelectColorValueProviderForm',
@@ -32,6 +33,10 @@ export default {
       type: Object,
       required: true,
     },
+    primary: {
+      type: Object,
+      required: true,
+    },
     fields: {
       type: Array,
       required: true,
@@ -43,7 +48,9 @@ export default {
   },
   computed: {
     selectFields() {
-      return this.fields.filter(({ type }) => type === 'single_select')
+      return [this.primary, ...this.fields].filter(
+        ({ type }) => type === SingleSelectFieldType.getType()
+      )
     },
     value() {
       return this.options && this.options.field_id
diff --git a/premium/web-frontend/modules/baserow_premium/decoratorValueProviders.js b/premium/web-frontend/modules/baserow_premium/decoratorValueProviders.js
index 14fd389a3..66401c71e 100644
--- a/premium/web-frontend/modules/baserow_premium/decoratorValueProviders.js
+++ b/premium/web-frontend/modules/baserow_premium/decoratorValueProviders.js
@@ -6,6 +6,9 @@ import {
   BackgroundColorViewDecoratorType,
   LeftBorderColorViewDecoratorType,
 } from '@baserow_premium/viewDecorators'
+import { uuid } from '@baserow/modules/core/utils/string'
+import { randomColor } from '@baserow/modules/core/utils/colors'
+import { matchSearchFilters } from '@baserow/modules/database/utils/view'
 
 export class SingleSelectColorValueProviderType extends DecoratorValueProviderType {
   static getType() {
@@ -52,6 +55,41 @@ export class ConditionalColorValueProviderType extends DecoratorValueProviderTyp
     return 'conditional_color'
   }
 
+  static getDefaultFilterConf(registry, { fields }) {
+    const field = fields[0]
+    const filter = { field: field.id }
+
+    const viewFilterTypes = registry.getAll('viewFilter')
+    const compatibleType = Object.values(viewFilterTypes).find(
+      (viewFilterType) => {
+        return viewFilterType.fieldIsCompatible(field)
+      }
+    )
+
+    filter.type = compatibleType.type
+    const viewFilterType = registry.get('viewFilter', filter.type)
+    filter.value = viewFilterType.getDefaultValue()
+    filter.preload_values = {}
+    filter.id = uuid()
+
+    return filter
+  }
+
+  static getDefaultColorConf(registry, { fields }, noFilter = false) {
+    return {
+      color: randomColor(),
+      operator: 'AND',
+      filters: noFilter
+        ? []
+        : [
+            ConditionalColorValueProviderType.getDefaultFilterConf(registry, {
+              fields,
+            }),
+          ],
+      uid: uuid(),
+    }
+  }
+
   getName() {
     const { i18n } = this.app
     return i18n.t('decoratorValueProviderType.conditionalColor')
@@ -67,6 +105,12 @@ export class ConditionalColorValueProviderType extends DecoratorValueProviderTyp
   }
 
   getValue({ options, fields, row }) {
+    const { $registry } = this.app
+    for (const { color, filters, operator } of options.colors) {
+      if (matchSearchFilters($registry, operator, filters, fields, row)) {
+        return color
+      }
+    }
     return ''
   }
 
@@ -77,4 +121,16 @@ export class ConditionalColorValueProviderType extends DecoratorValueProviderTyp
   getFormComponent() {
     return ConditionalColorValueProviderForm
   }
+
+  getDefaultConfiguration({ fields }) {
+    const { $registry } = this.app
+    return {
+      default: null,
+      colors: [
+        ConditionalColorValueProviderType.getDefaultColorConf($registry, {
+          fields,
+        }),
+      ],
+    }
+  }
 }
diff --git a/premium/web-frontend/modules/baserow_premium/locales/en.json b/premium/web-frontend/modules/baserow_premium/locales/en.json
index 0cf0f7c77..921e943c2 100644
--- a/premium/web-frontend/modules/baserow_premium/locales/en.json
+++ b/premium/web-frontend/modules/baserow_premium/locales/en.json
@@ -237,5 +237,10 @@
     },
     "singleSelectColorValueProviderForm": {
         "chooseAColor": "Which single select field should the row be colored by?"
+    },
+    "conditionalColorValueProviderForm": {
+        "addCondition": "add condition",
+        "colorAlwaysApply": "This color applies by default. You can add conditions by clicking on the \"Add condition\" button.",
+        "addColor": "add color"
     }
 }
diff --git a/web-frontend/modules/core/assets/scss/components/filters.scss b/web-frontend/modules/core/assets/scss/components/filters.scss
index 94a173db8..7f35fd21a 100644
--- a/web-frontend/modules/core/assets/scss/components/filters.scss
+++ b/web-frontend/modules/core/assets/scss/components/filters.scss
@@ -1,5 +1,6 @@
 .filters {
   padding: 12px;
+  width: 550px;
 
   .dropdown__selected {
     @extend %ellipsis;
@@ -23,34 +24,33 @@
 
 .filters__item {
   position: relative;
-  display: flex;
+  display: grid;
   align-items: center;
+  // 142px = 20 + 82 + 10 * 4 (gaps)
+  grid-template-columns: 20px 82px calc(50% - 142px) 22% 28%;
   padding: 6px 0;
   border-radius: 3px;
+  margin-left: 5px;
+  column-gap: 10px;
 
   &:not(:last-child) {
     margin-bottom: 6px;
   }
 
   &.filters__item--loading {
-    padding-left: 32px;
-
     &::before {
       content: '';
       margin-top: -7px;
 
       @include loading(14px);
-      @include absolute(50%, auto, 0, 10px);
+      @include absolute(50%, auto, 0, -2px);
     }
   }
 }
 
 .filters__remove {
-  flex: 0 0 32px;
-  width: 32px;
   color: $color-primary-900;
   line-height: 30px;
-  text-align: center;
 
   &:hover {
     text-decoration: none;
@@ -58,32 +58,16 @@
   }
 
   .filters__item--loading & {
-    display: none;
+    visibility: hidden;
   }
 }
 
 .filters__operator {
-  flex: 0 0 72px;
-  width: 72px;
-  margin-right: 10px;
-
   span {
     padding-left: 12px;
   }
 }
 
-.filters__field {
-  margin-right: 10px;
-
-  @include filter-dropdown-width(100px);
-}
-
-.filters__type {
-  margin-right: 10px;
-
-  @include filter-dropdown-width(100px);
-}
-
 .filters__value {
   flex: 0 0;
 }
@@ -96,7 +80,6 @@
 }
 
 .filters__value-input {
-  width: 130px;
   padding-top: 0;
   padding-bottom: 0;
   line-height: 30px;
@@ -113,10 +96,6 @@
   color: $color-neutral-400;
 }
 
-.filters__value-dropdown {
-  width: 130px;
-}
-
 .filters__value-rating {
   border: solid 1px $color-neutral-400;
   border-radius: 3px;
@@ -128,13 +107,13 @@
 
   display: block;
   position: relative;
-  width: 130px;
   color: $color-primary-900;
   line-height: 30px;
   height: 30px;
   border: solid 1px $color-neutral-400;
   border-radius: 3px;
   padding: 0 10px;
+  background-color: $white;
 
   &:hover {
     text-decoration: none;
@@ -150,6 +129,16 @@
       border-color: $color-neutral-400;
     }
   }
+
+  &.filters__value-link-row--loading {
+    &::before {
+      content: '';
+      margin-top: -7px;
+
+      @include loading(14px);
+      @include absolute(50%, auto, 0, calc(50% - 7px));
+    }
+  }
 }
 
 .filters__value-link-row-choose {
diff --git a/web-frontend/modules/core/components/Picker.vue b/web-frontend/modules/core/components/Picker.vue
index a3518cc4c..6648fe442 100644
--- a/web-frontend/modules/core/components/Picker.vue
+++ b/web-frontend/modules/core/components/Picker.vue
@@ -7,8 +7,8 @@
     >
       <i class="dropdown__selected-icon fas" :class="'fa-' + icon" />
       {{ name }}
+      <i class="dropdown__toggle-icon fas fa-caret-down"></i>
     </a>
-    <i class="dropdown__toggle-icon fas fa-caret-down"></i>
     <Context ref="pickerContext" class="picker__context">
       <slot :hidePicker="hide" />
     </Context>
diff --git a/web-frontend/modules/core/directives/sortable.js b/web-frontend/modules/core/directives/sortable.js
index da362ced3..f695dfe18 100644
--- a/web-frontend/modules/core/directives/sortable.js
+++ b/web-frontend/modules/core/directives/sortable.js
@@ -16,18 +16,18 @@ import { findScrollableParent } from '@baserow/modules/core/utils/dom'
  * <div
  *   v-for="item in items"
  *   :key="item.id"
- *   v-sortable="{ id: item.id, update: order }"
+ *   v-sortable="{ id: item.id, update: onUpdate }"
  * ></div>
  *
  * export default {
  *   data() {
  *     return {
- *       items: [{'id': 1, order: 1}, {'id': 2, order: 2}, {'id': 3, order: 3}]
+ *       items: [{'id': 25, order: 1}, {'id': 27, order: 2}, {'id': 30, order: 3}]
  *     }
  *   },
  *   methods: {
- *     order(order) {
- *       console.log(order) // [1, 2, 3]
+ *     onUpdate(itemIds) {
+ *       console.log(itemIds) // [25, 27, 30]
  *     },
  *   },
  * }
@@ -76,6 +76,12 @@ export default {
 
       parent = el.parentNode
       scrollableParent = findScrollableParent(parent) || parent
+
+      // If the parent container is not positioned, add the position automatically.
+      if (getComputedStyle(parent).position === 'static') {
+        parent.style.position = 'relative'
+      }
+
       indicator = document.createElement('div')
       indicator.classList.add('sortable-position-indicator')
       parent.insertBefore(indicator, parent.firstChild)
diff --git a/web-frontend/modules/database/components/field/FieldRatingSubForm.vue b/web-frontend/modules/database/components/field/FieldRatingSubForm.vue
index 64b524030..e352ac9e4 100644
--- a/web-frontend/modules/database/components/field/FieldRatingSubForm.vue
+++ b/web-frontend/modules/database/components/field/FieldRatingSubForm.vue
@@ -6,7 +6,7 @@
       }}</label>
       <div class="control__elements">
         <a
-          :ref="'color-select'"
+          ref="color-select"
           :class="'rating-field__color' + ' background-color--' + values.color"
           @click="openColor()"
         >
diff --git a/web-frontend/modules/database/components/view/ViewDecoratorContext.vue b/web-frontend/modules/database/components/view/ViewDecoratorContext.vue
index ba11d0c55..0bd930b15 100644
--- a/web-frontend/modules/database/components/view/ViewDecoratorContext.vue
+++ b/web-frontend/modules/database/components/view/ViewDecoratorContext.vue
@@ -59,8 +59,9 @@
             v-if="dec.valueProviderType"
             :view="view"
             :table="table"
-            :fields="allFields"
-            :read-only="readOnly || dec.decoration._.loading"
+            :primary="primary"
+            :fields="fields"
+            :read-only="readOnly"
             :options="dec.decoration.value_provider_conf"
             @update="updateDecorationOptions(dec.decoration, $event)"
           />
@@ -192,7 +193,7 @@ export default {
           value_provider_type: valueProviderType.getType(),
           value_provider_conf: valueProviderType.getDefaultConfiguration({
             view: this.view,
-            fields: this.fields,
+            fields: this.allFields,
           }),
         },
         decoration,
diff --git a/web-frontend/modules/database/components/view/ViewFieldConditionsForm.vue b/web-frontend/modules/database/components/view/ViewFieldConditionsForm.vue
new file mode 100644
index 000000000..e9c130e1e
--- /dev/null
+++ b/web-frontend/modules/database/components/view/ViewFieldConditionsForm.vue
@@ -0,0 +1,255 @@
+<template>
+  <div>
+    <!--
+      Here we use the index as key to avoid loosing focus when filter id change.
+    -->
+    <div
+      v-for="(filter, index) in filters"
+      :key="index"
+      class="filters__item"
+      :class="{
+        'filters__item--loading': filter._ && filter._.loading,
+      }"
+    >
+      <a
+        v-if="!disableFilter"
+        class="filters__remove"
+        @click="deleteFilter(filter)"
+      >
+        <i class="fas fa-times"></i>
+      </a>
+      <div class="filters__operator">
+        <span v-if="index === 0">{{ $t('viewFilterContext.where') }}</span>
+        <Dropdown
+          v-if="index === 1 && !disableFilter"
+          :value="filterType"
+          :show-search="false"
+          class="dropdown--floating dropdown--tiny"
+          @input="selectBooleanOperator($event)"
+        >
+          <DropdownItem
+            :name="$t('viewFilterContext.and')"
+            value="AND"
+          ></DropdownItem>
+          <DropdownItem
+            :name="$t('viewFilterContext.or')"
+            value="OR"
+          ></DropdownItem>
+        </Dropdown>
+        <span v-if="index > 1 || (index > 0 && disableFilter)">
+          {{
+            filterType === 'AND'
+              ? $t('viewFilterContext.and')
+              : $t('viewFilterContext.or')
+          }}
+        </span>
+      </div>
+      <div class="filters__field">
+        <Dropdown
+          :value="filter.field"
+          :disabled="disableFilter"
+          class="dropdown--floating dropdown--tiny"
+          @input="updateFilter(filter, { field: $event })"
+        >
+          <DropdownItem
+            :key="'primary-' + primary.id"
+            :name="primary.name"
+            :value="primary.id"
+            :disabled="hasNoCompatibleFilterTypes(primary, filterTypes)"
+          ></DropdownItem>
+          <DropdownItem
+            v-for="field in fields"
+            :key="'field-' + field.id"
+            :name="field.name"
+            :value="field.id"
+            :disabled="hasNoCompatibleFilterTypes(field, filterTypes)"
+          ></DropdownItem>
+        </Dropdown>
+      </div>
+      <div class="filters__type">
+        <Dropdown
+          :disabled="disableFilter"
+          :value="filter.type"
+          class="dropdown--floating dropdown--tiny"
+          @input="updateFilter(filter, { type: $event })"
+        >
+          <DropdownItem
+            v-for="fType in allowedFilters(
+              filterTypes,
+              primary,
+              fields,
+              filter.field
+            )"
+            :key="fType.type"
+            :name="fType.getName()"
+            :value="fType.type"
+          ></DropdownItem>
+        </Dropdown>
+      </div>
+      <div class="filters__value">
+        <component
+          :is="getInputComponent(filter.type, filter.field)"
+          :ref="`filter-value-${index}`"
+          :filter="filter"
+          :view="view"
+          :fields="fields"
+          :primary="primary"
+          :disabled="disableFilter"
+          :read-only="readOnly"
+          @input="updateFilter(filter, { value: $event })"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ViewFieldConditionsForm',
+  props: {
+    filters: {
+      type: Array,
+      required: true,
+    },
+    disableFilter: {
+      type: Boolean,
+      required: true,
+    },
+    filterType: {
+      type: String,
+      required: true,
+    },
+    primary: {
+      type: Object,
+      required: true,
+    },
+    fields: {
+      type: Array,
+      required: true,
+    },
+    view: {
+      type: Object,
+      required: true,
+    },
+    readOnly: {
+      type: Boolean,
+      required: true,
+    },
+  },
+  computed: {
+    filterTypes() {
+      return this.$registry.getAll('viewFilter')
+    },
+    localFilters() {
+      // Copy the filters
+      return [...this.filters]
+    },
+  },
+  watch: {
+    /**
+     * When a filter has been created or removed we want to focus on last value. By
+     * watching localFilters instead of filters, the new and old values are differents.
+     */
+    localFilters(value, old) {
+      if (value.length !== old.length) {
+        this.$nextTick(() => {
+          this.focusValue(value.length - 1)
+        })
+      }
+    },
+  },
+  methods: {
+    focusValue(position) {
+      const ref = `filter-value-${position}`
+      if (
+        position >= 0 &&
+        Object.prototype.hasOwnProperty.call(this.$refs, ref) &&
+        this.$refs[ref][0] &&
+        Object.prototype.hasOwnProperty.call(this.$refs[ref][0], 'focus')
+      ) {
+        this.$refs[ref][0].focus()
+      }
+    },
+    /**
+     * Indicates if the field has any compatible filter types.
+     */
+    hasNoCompatibleFilterTypes(field, filterTypes) {
+      for (const type in filterTypes) {
+        if (filterTypes[type].fieldIsCompatible(field)) {
+          return false
+        }
+      }
+      return true
+    },
+    /**
+     * Returns a list of filter types that are allowed for the given fieldId.
+     */
+    allowedFilters(filterTypes, primary, fields, fieldId) {
+      const field =
+        primary.id === fieldId ? primary : fields.find((f) => f.id === fieldId)
+      return Object.values(filterTypes).filter((filterType) => {
+        return field !== undefined && filterType.fieldIsCompatible(field)
+      })
+    },
+    deleteFilter(filter) {
+      this.$emit('deleteFilter', filter)
+    },
+    /**
+     * Updates a filter with the given values. Some data manipulation will also be done
+     * because some filter types are not compatible with certain field types.
+     */
+    updateFilter(filter, values) {
+      const field = Object.prototype.hasOwnProperty.call(values, 'field')
+        ? values.field
+        : filter.field
+      const type = Object.prototype.hasOwnProperty.call(values, 'type')
+        ? values.type
+        : filter.type
+      const value = Object.prototype.hasOwnProperty.call(values, 'value')
+        ? values.value
+        : filter.value
+
+      // If the field has changed we need to check if the filter type is compatible
+      // and if not we are going to choose the first compatible type.
+      if (Object.prototype.hasOwnProperty.call(values, 'field')) {
+        const allowedFilterTypes = this.allowedFilters(
+          this.filterTypes,
+          this.primary,
+          this.fields,
+          field
+        ).map((filter) => filter.type)
+        if (!allowedFilterTypes.includes(type)) {
+          values.type = allowedFilterTypes[0]
+        }
+      }
+
+      // If the type or value has changed it could be that the value needs to be
+      // formatted or prepared.
+      if (
+        Object.prototype.hasOwnProperty.call(values, 'type') ||
+        Object.prototype.hasOwnProperty.call(values, 'value')
+      ) {
+        const filterType = this.$registry.get('viewFilter', type)
+        values.value = filterType.prepareValue(value)
+      }
+
+      this.$emit('updateFilter', { filter, values })
+    },
+
+    selectBooleanOperator(value) {
+      this.$emit('selectOperator', value)
+    },
+    /**
+     * Returns the input component related to the filter type. This component is
+     * responsible for updating the filter value.
+     */
+    getInputComponent(type, fieldId) {
+      const field =
+        this.primary.id === fieldId
+          ? this.primary
+          : this.fields.find(({ id }) => id === fieldId)
+      return this.$registry.get('viewFilter', type).getInputComponent(field)
+    },
+  },
+}
+</script>
diff --git a/web-frontend/modules/database/components/view/ViewFilterForm.vue b/web-frontend/modules/database/components/view/ViewFilterForm.vue
index e8e97f528..bd0cb4d95 100644
--- a/web-frontend/modules/database/components/view/ViewFilterForm.vue
+++ b/web-frontend/modules/database/components/view/ViewFilterForm.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <div v-show="view.filters.length === 0">
+    <div v-if="view.filters.length === 0">
       <div class="filters__none">
         <div class="filters__none-title">
           {{ $t('viewFilterContext.noFilterTitle') }}
@@ -10,110 +10,18 @@
         </div>
       </div>
     </div>
-    <div
-      v-for="(filter, index) in view.filters"
-      :key="filter.id"
-      class="filters__item"
-      :class="{
-        'filters__item--loading': filter._.loading,
-      }"
-    >
-      <a
-        v-if="!disableFilter"
-        class="filters__remove"
-        @click.stop.prevent="deleteFilter(filter)"
-      >
-        <i class="fas fa-times"></i>
-      </a>
-      <div class="filters__operator">
-        <span v-if="index === 0">{{ $t('viewFilterContext.where') }}</span>
-        <Dropdown
-          v-if="index === 1 && !disableFilter"
-          :value="view.filter_type"
-          :show-search="false"
-          class="dropdown--floating dropdown--tiny"
-          @input="updateView(view, { filter_type: $event })"
-        >
-          <DropdownItem
-            :name="$t('viewFilterContext.and')"
-            value="AND"
-          ></DropdownItem>
-          <DropdownItem
-            :name="$t('viewFilterContext.or')"
-            value="OR"
-          ></DropdownItem>
-        </Dropdown>
-        <span
-          v-if="
-            (index > 1 || (index > 0 && disableFilter)) &&
-            view.filter_type === 'AND'
-          "
-          >{{ $t('viewFilterContext.and') }}</span
-        >
-        <span
-          v-if="
-            (index > 1 || (index > 0 && disableFilter)) &&
-            view.filter_type === 'OR'
-          "
-          >{{ $t('viewFilterContext.or') }}</span
-        >
-      </div>
-      <div class="filters__field">
-        <Dropdown
-          :value="filter.field"
-          :disabled="disableFilter"
-          class="dropdown--floating dropdown--tiny"
-          @input="updateFilter(filter, { field: $event })"
-        >
-          <DropdownItem
-            :key="'filter-field-' + filter.id + '-' + primary.id"
-            :name="primary.name"
-            :value="primary.id"
-            :disabled="hasNoCompatibleFilterTypes(primary, filterTypes)"
-          ></DropdownItem>
-          <DropdownItem
-            v-for="field in fields"
-            :key="'filter-field-' + filter.id + '-' + field.id"
-            :name="field.name"
-            :value="field.id"
-            :disabled="hasNoCompatibleFilterTypes(field, filterTypes)"
-          ></DropdownItem>
-        </Dropdown>
-      </div>
-      <div class="filters__type">
-        <Dropdown
-          :disabled="disableFilter"
-          :value="filter.type"
-          class="dropdown--floating dropdown--tiny"
-          @input="updateFilter(filter, { type: $event })"
-        >
-          <DropdownItem
-            v-for="filterType in allowedFilters(
-              filterTypes,
-              primary,
-              fields,
-              filter.field
-            )"
-            :key="filterType.type"
-            :name="filterType.getName()"
-            :value="filterType.type"
-          ></DropdownItem>
-        </Dropdown>
-      </div>
-      <div class="filters__value">
-        <component
-          :is="getInputComponent(filter.type, filter.field)"
-          :ref="'filter-' + filter.id + '-value'"
-          :filter="filter"
-          :view="view"
-          :fields="fields"
-          :primary="primary"
-          :disabled="disableFilter"
-          :read-only="readOnly"
-          @input="updateFilter(filter, { value: $event })"
-        />
-      </div>
-    </div>
+    <ViewFieldConditionsForm
+      :filters="view.filters"
+      :disable-filter="disableFilter"
+      :filter-type="view.filter_type"
+      :primary="primary"
+      :fields="fields"
+      :view="view"
+      :read-only="readOnly"
+      @deleteFilter="deleteFilter($event)"
+      @updateFilter="updateFilter($event)"
+      @selectOperator="updateView(view, { filter_type: $event })"
+    />
     <div v-if="!disableFilter" class="filters_footer">
       <a class="filters__add" @click.prevent="addFilter()">
         <i class="fas fa-plus"></i>
@@ -132,9 +40,13 @@
 
 <script>
 import { notifyIf } from '@baserow/modules/core/utils/error'
+import ViewFieldConditionsForm from '@baserow/modules/database/components/view/ViewFieldConditionsForm'
 
 export default {
   name: 'ViewFilterForm',
+  components: {
+    ViewFieldConditionsForm,
+  },
   props: {
     primary: {
       type: Object,
@@ -162,54 +74,10 @@ export default {
       return this.$registry.getAll('viewFilter')
     },
   },
-  beforeMount() {
-    this.$bus.$on('view-filter-created', this.filterCreated)
-  },
-  beforeDestroy() {
-    this.$bus.$off('view-filter-created', this.filterCreated)
-  },
   methods: {
-    /**
-     * When the filter has been created we want to focus on the value.
-     */
-    filterCreated({ filter }) {
-      this.$nextTick(() => {
-        this.focusValue(filter)
-      })
-    },
-    focusValue(filter) {
-      const ref = 'filter-' + filter.id + '-value'
-      if (
-        Object.prototype.hasOwnProperty.call(this.$refs, ref) &&
-        Object.prototype.hasOwnProperty.call(this.$refs[ref][0], 'focus')
-      ) {
-        this.$refs[ref][0].focus()
-      }
-    },
-    /**
-     * Indicates if the field has any compatible filter types.
-     */
-    hasNoCompatibleFilterTypes(field, filterTypes) {
-      for (const type in filterTypes) {
-        if (filterTypes[type].fieldIsCompatible(field)) {
-          return false
-        }
-      }
-      return true
-    },
-    /**
-     * Returns a list of filter types that are allowed for the given fieldId.
-     */
-    allowedFilters(filterTypes, primary, fields, fieldId) {
-      const field =
-        primary.id === fieldId ? primary : fields.find((f) => f.id === fieldId)
-      return Object.values(filterTypes).filter((filterType) => {
-        return field !== undefined && filterType.fieldIsCompatible(field)
-      })
-    },
-    async addFilter() {
+    async addFilter(values) {
       try {
-        const { filter } = await this.$store.dispatch('view/createFilter', {
+        await this.$store.dispatch('view/createFilter', {
           view: this.view,
           field: this.primary,
           values: {
@@ -219,11 +87,6 @@ export default {
           readOnly: this.readOnly,
         })
         this.$emit('changed')
-
-        // Wait for the filter to be rendered and then focus on the value input.
-        this.$nextTick(() => {
-          this.focusValue(filter)
-        })
       } catch (error) {
         notifyIf(error, 'view')
       }
@@ -244,41 +107,7 @@ export default {
      * Updates a filter with the given values. Some data manipulation will also be done
      * because some filter types are not compatible with certain field types.
      */
-    async updateFilter(filter, values) {
-      const field = Object.prototype.hasOwnProperty.call(values, 'field')
-        ? values.field
-        : filter.field
-      const type = Object.prototype.hasOwnProperty.call(values, 'type')
-        ? values.type
-        : filter.type
-      const value = Object.prototype.hasOwnProperty.call(values, 'value')
-        ? values.value
-        : filter.value
-
-      // If the field has changed we need to check if the filter type is compatible
-      // and if not we are going to choose the first compatible type.
-      if (Object.prototype.hasOwnProperty.call(values, 'field')) {
-        const allowedFilterTypes = this.allowedFilters(
-          this.filterTypes,
-          this.primary,
-          this.fields,
-          field
-        ).map((filter) => filter.type)
-        if (!allowedFilterTypes.includes(type)) {
-          values.type = allowedFilterTypes[0]
-        }
-      }
-
-      // If the type or value has changed it could be that the value needs to be
-      // formatted or prepared.
-      if (
-        Object.prototype.hasOwnProperty.call(values, 'type') ||
-        Object.prototype.hasOwnProperty.call(values, 'value')
-      ) {
-        const filterType = this.$registry.get('viewFilter', type)
-        values.value = filterType.prepareValue(value)
-      }
-
+    async updateFilter({ filter, values }) {
       try {
         await this.$store.dispatch('view/updateFilter', {
           filter,
@@ -310,14 +139,6 @@ export default {
 
       this.$store.dispatch('view/setItemLoading', { view, value: false })
     },
-    /**
-     * Returns the input component related to the filter type. This component is
-     * responsible for updating the filter value.
-     */
-    getInputComponent(type, fieldId) {
-      const field = this.fields.find(({ id }) => id === fieldId)
-      return this.$registry.get('viewFilter', type).getInputComponent(field)
-    },
   },
 }
 </script>
diff --git a/web-frontend/modules/database/components/view/ViewFilterTypeLinkRow.vue b/web-frontend/modules/database/components/view/ViewFilterTypeLinkRow.vue
index 7db8f84a9..902d4fa11 100644
--- a/web-frontend/modules/database/components/view/ViewFilterTypeLinkRow.vue
+++ b/web-frontend/modules/database/components/view/ViewFilterTypeLinkRow.vue
@@ -11,15 +11,22 @@
   <a
     v-else
     class="filters__value-link-row"
-    :class="{ 'filters__value-link-row--disabled': disabled }"
+    :class="{
+      'filters__value-link-row--disabled': disabled,
+      'filters__value-link-row--loading': loading,
+    }"
     @click.prevent="!disabled && $refs.selectModal.show()"
   >
-    <template v-if="valid">
-      {{ name || $t('viewFilterTypeLinkRow.unnamed', { value: filter.value }) }}
+    <template v-if="!loading">
+      <template v-if="valid">
+        {{
+          name || $t('viewFilterTypeLinkRow.unnamed', { value: filter.value })
+        }}
+      </template>
+      <div v-else class="filters__value-link-row-choose">
+        {{ $t('viewFilterTypeLinkRow.choose') }}
+      </div>
     </template>
-    <div v-else class="filters__value-link-row-choose">
-      {{ $t('viewFilterTypeLinkRow.choose') }}
-    </div>
     <SelectRowModal
       v-if="!disabled"
       ref="selectModal"
@@ -35,6 +42,7 @@ import PaginatedDropdown from '@baserow/modules/core/components/PaginatedDropdow
 import SelectRowModal from '@baserow/modules/database/components/row/SelectRowModal'
 import viewFilter from '@baserow/modules/database/mixins/viewFilter'
 import ViewService from '@baserow/modules/database/services/view'
+import RowService from '@baserow/modules/database/services/row'
 
 export default {
   name: 'ViewFilterTypeLinkRow',
@@ -43,41 +51,55 @@ export default {
   data() {
     return {
       name: '',
+      rowInfo: null,
+      loading: false,
     }
   },
   computed: {
     valid() {
-      return this.isValidValue(this.filter.value)
+      return isNumeric(this.filter.value)
     },
   },
   watch: {
-    'filter.preload_values'(value) {
-      this.setNameFromPreloadValues(value)
+    'filter.value'() {
+      this.setName()
     },
   },
   mounted() {
-    this.setNameFromPreloadValues(this.filter.preload_values)
+    this.setName()
   },
   methods: {
-    setNameFromRow(row, primary) {
-      this.name = this.$registry
-        .get('field', primary.type)
-        .toHumanReadableString(primary, row[`field_${primary.id}`])
-    },
-    setNameFromPreloadValues(values) {
-      if (Object.prototype.hasOwnProperty.call(values, 'display_name')) {
-        this.name = values.display_name
-      }
-    },
-    isValidValue() {
-      if (!isNumeric(this.filter.value)) {
-        return false
-      }
+    async setName() {
+      const { value, preload_values: { display_name: displayName } = {} } =
+        this.filter
 
-      return true
+      if (!value) {
+        this.name = ''
+      } else if (displayName) {
+        // set the name from preload_values
+        this.name = displayName
+      } else if (this.rowInfo) {
+        // Set the name from previous row info
+        const { row, primary } = this.rowInfo
+        this.name = this.$registry
+          .get('field', primary.type)
+          .toHumanReadableString(primary, row[`field_${primary.id}`])
+        this.rowInfo = null
+      } else {
+        // Get the name from server
+        this.loading = true
+        try {
+          this.name = await RowService(this.$client).getName(
+            this.field.link_row_table,
+            value
+          )
+        } finally {
+          this.loading = false
+        }
+      }
     },
     setValue({ row, primary }) {
-      this.setNameFromRow(row, primary)
+      this.rowInfo = { row, primary }
       this.$emit('input', row.id.toString())
     },
     fetchPage(page, search) {
diff --git a/web-frontend/modules/database/components/view/grid/GridView.vue b/web-frontend/modules/database/components/view/grid/GridView.vue
index 59a050cc5..03e041241 100644
--- a/web-frontend/modules/database/components/view/grid/GridView.vue
+++ b/web-frontend/modules/database/components/view/grid/GridView.vue
@@ -16,6 +16,7 @@
       ref="left"
       class="grid-view__left"
       :fields="leftFields"
+      :all-table-fields="allTableFields"
       :table="table"
       :view="view"
       :include-field-width-handles="false"
@@ -64,6 +65,7 @@
       ref="right"
       class="grid-view__right"
       :fields="visibleFields"
+      :all-table-fields="allTableFields"
       :table="table"
       :view="view"
       :include-add-field="true"
@@ -276,6 +278,9 @@ export default {
     leftWidth() {
       return this.leftFieldsWidth + this.gridViewRowDetailsWidth
     },
+    allTableFields() {
+      return [this.primary, ...this.fields]
+    },
   },
   watch: {
     fieldOptions: {
diff --git a/web-frontend/modules/database/components/view/grid/GridViewRow.vue b/web-frontend/modules/database/components/view/grid/GridViewRow.vue
index eebcad7b0..500a3c73b 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewRow.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewRow.vue
@@ -70,7 +70,7 @@
               :is="dec.component"
               v-for="dec in firstCellDecorations"
               :key="dec.decoration.id"
-              :value="dec.propsFn(row).value"
+              v-bind="dec.propsFn(row)"
             />
           </div>
         </div>
diff --git a/web-frontend/modules/database/components/view/grid/GridViewRows.vue b/web-frontend/modules/database/components/view/grid/GridViewRows.vue
index fd7a1dfbd..4aba9869e 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewRows.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewRows.vue
@@ -41,6 +41,10 @@ export default {
       type: Array,
       required: true,
     },
+    allTableFields: {
+      type: Array,
+      required: true,
+    },
     leftOffset: {
       type: Number,
       required: false,
@@ -86,11 +90,12 @@ export default {
             'decoratorValueProvider',
             decoration.value_provider_type
           )
+
           deco.propsFn = (row) => {
             return {
               value: deco.valueProviderType.getValue({
                 row,
-                fields: this.allFields,
+                fields: this.allTableFields,
                 options: decoration.value_provider_conf,
               }),
             }
diff --git a/web-frontend/modules/database/components/view/grid/GridViewSection.vue b/web-frontend/modules/database/components/view/grid/GridViewSection.vue
index 7cc02244d..34ea7ade8 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewSection.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewSection.vue
@@ -52,6 +52,7 @@
             :view="view"
             :fields="fieldsToRender"
             :all-fields="fields"
+            :all-table-fields="allTableFields"
             :left-offset="fieldsLeftOffset"
             :include-row-details="includeRowDetails"
             :read-only="readOnly"
@@ -126,6 +127,10 @@ export default {
       type: Array,
       required: true,
     },
+    allTableFields: {
+      type: Array,
+      required: true,
+    },
     table: {
       type: Object,
       required: true,
diff --git a/web-frontend/modules/database/services/row.js b/web-frontend/modules/database/services/row.js
index 603019790..bea33ab4d 100644
--- a/web-frontend/modules/database/services/row.js
+++ b/web-frontend/modules/database/services/row.js
@@ -1,4 +1,28 @@
+let pendingGetQueries = {}
+let delay = null
+const GRACE_DELAY = 50 // ms before querying the backend with a get query
+
 export default (client) => {
+  const getNameCallback = async () => {
+    const config = {}
+    config.params = Object.fromEntries(
+      Object.entries(pendingGetQueries).map(([tableId, rows]) => {
+        const rowIds = Object.keys(rows)
+        return [`table__${tableId}`, rowIds.join(',')]
+      })
+    )
+
+    const { data } = await client.get(`/database/rows/names/`, config)
+
+    Object.entries(data).forEach(([tableId, rows]) => {
+      Object.entries(rows).forEach(([rowId, rowName]) => {
+        pendingGetQueries[tableId][rowId].forEach((resolve) => resolve(rowName))
+      })
+    })
+    pendingGetQueries = {}
+    delay = null
+  }
+
   return {
     get(tableId, rowId) {
       return client.get(`/database/rows/table/${tableId}/${rowId}/`)
@@ -17,6 +41,25 @@ export default (client) => {
 
       return client.get(`/database/rows/table/${tableId}/`, config)
     },
+    /**
+     * Returns the name of specified table row. Batch consecutive queries into one
+     * during the defined GRACE_TIME.
+     */
+    getName(tableId, rowId) {
+      return new Promise((resolve) => {
+        clearTimeout(delay)
+
+        if (!pendingGetQueries[tableId]) {
+          pendingGetQueries[tableId] = {}
+        }
+        if (!pendingGetQueries[tableId][rowId]) {
+          pendingGetQueries[tableId][rowId] = []
+        }
+        pendingGetQueries[tableId][rowId].push(resolve)
+
+        delay = setTimeout(getNameCallback, GRACE_DELAY)
+      })
+    },
     create(tableId, values, beforeId = null) {
       const config = { params: {} }
 
diff --git a/web-frontend/modules/database/store/view.js b/web-frontend/modules/database/store/view.js
index d68ce5355..f1ed1cb15 100644
--- a/web-frontend/modules/database/store/view.js
+++ b/web-frontend/modules/database/store/view.js
@@ -479,6 +479,10 @@ export const actions = {
 
     commit('ADD_FILTER', { view, filter })
 
+    if (emitEvent) {
+      this.$bus.$emit('view-filter-created', { view, filter })
+    }
+
     try {
       if (!readOnly) {
         const { data } = await FilterService(this.$client).create(
@@ -487,10 +491,6 @@ export const actions = {
         )
         commit('FINALIZE_FILTER', { view, oldId: filter.id, id: data.id })
       }
-
-      if (emitEvent) {
-        this.$bus.$emit('view-filter-created', { view, filter })
-      }
     } catch (error) {
       commit('DELETE_FILTER', { view, id: filter.id })
       throw error
diff --git a/web-frontend/package.json b/web-frontend/package.json
index 6dbbdd0c5..9919e0f09 100644
--- a/web-frontend/package.json
+++ b/web-frontend/package.json
@@ -14,6 +14,7 @@
     "dev": "nuxt --hostname 0.0.0.0",
     "start": "nuxt start --hostname 0.0.0.0",
     "eslint": "eslint -c .eslintrc.js --ext .js,.vue . ../premium/web-frontend",
+    "lint": "yarn eslint && yarn stylelint",
     "stylelint": "stylelint **/*.scss ../premium/web-frontend/**/*.scss --syntax scss",
     "jest": "jest --verbose false",
     "test": "yarn jest"
@@ -79,4 +80,4 @@
     "stylelint-webpack-plugin": "^3.0.1",
     "vue-jest": "^3.0.3"
   }
-}
\ No newline at end of file
+}
diff --git a/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap b/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap
index 62e1db44a..c98d5fe88 100644
--- a/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap
+++ b/web-frontend/test/unit/database/components/view/__snapshots__/viewDecoratorContext.spec.js.snap
@@ -207,13 +207,12 @@ exports[`GridViewRows component with decoration Should show can add decorator to
                   />
                   
     Fake value provider
-  
+    
+                  <i
+                    class="dropdown__toggle-icon fas fa-caret-down"
+                  />
                 </a>
                  
-                <i
-                  class="dropdown__toggle-icon fas fa-caret-down"
-                />
-                 
               </div>
             </div>
              
@@ -510,13 +509,12 @@ exports[`GridViewRows component with decoration Should show unavailable decorato
                   />
                   
     Fake value provider
-  
+    
+                  <i
+                    class="dropdown__toggle-icon fas fa-caret-down"
+                  />
                 </a>
                  
-                <i
-                  class="dropdown__toggle-icon fas fa-caret-down"
-                />
-                 
               </div>
             </div>
              
@@ -762,13 +760,12 @@ exports[`GridViewRows component with decoration View with decoration configured
                 />
                 
     Fake value provider
-  
+    
+                <i
+                  class="dropdown__toggle-icon fas fa-caret-down"
+                />
               </a>
                
-              <i
-                class="dropdown__toggle-icon fas fa-caret-down"
-              />
-               
             </div>
           </div>
            
diff --git a/web-frontend/test/unit/database/components/view/__snapshots__/viewFilterForm.spec.js.snap b/web-frontend/test/unit/database/components/view/__snapshots__/viewFilterForm.spec.js.snap
index 06fe8fc14..c528b5f5d 100644
--- a/web-frontend/test/unit/database/components/view/__snapshots__/viewFilterForm.spec.js.snap
+++ b/web-frontend/test/unit/database/components/view/__snapshots__/viewFilterForm.spec.js.snap
@@ -2,53 +2,7 @@
 
 exports[`ViewFilterForm component Default view filter component 1`] = `
 <div>
-  <div
-    style="display: none;"
-  >
-    <div
-      class="filters__none"
-    >
-      <div
-        class="filters__none-title"
-      >
-        
-        viewFilterContext.noFilterTitle
-      
-      </div>
-       
-      <div
-        class="filters__none-description"
-      >
-        
-        viewFilterContext.noFilterText
-      
-      </div>
-    </div>
-  </div>
-    
-  <div
-    class="filters_footer"
-  >
-    <a
-      class="filters__add"
-    >
-      <i
-        class="fas fa-plus"
-      />
-      
-      viewFilterContext.addFilter
-    </a>
-     
-    <!---->
-  </div>
-</div>
-`;
-
-exports[`ViewFilterForm component Full view filter component 1`] = `
-<div>
-  <div
-    style="display: none;"
-  >
+  <div>
     <div
       class="filters__none"
     >
@@ -70,629 +24,651 @@ exports[`ViewFilterForm component Full view filter component 1`] = `
     </div>
   </div>
    
+  <div />
+   
   <div
-    class="filters__item"
+    class="filters_footer"
   >
     <a
-      class="filters__remove"
+      class="filters__add"
     >
       <i
-        class="fas fa-times"
+        class="fas fa-plus"
       />
+      
+      viewFilterContext.addFilter
     </a>
      
+    <!---->
+  </div>
+</div>
+`;
+
+exports[`ViewFilterForm component Full view filter component 1`] = `
+<div>
+  <!---->
+   
+  <div>
     <div
-      class="filters__operator"
+      class="filters__item"
     >
-      <span>
-        viewFilterContext.where
-      </span>
-       
-      <!---->
-       
-      <!---->
-       
-      <!---->
-    </div>
-     
-    <div
-      class="filters__field"
-    >
-      <div
-        class="dropdown dropdown--floating dropdown--tiny"
+      <a
+        class="filters__remove"
       >
-        <a
-          class="dropdown__selected"
+        <i
+          class="fas fa-times"
+        />
+      </a>
+       
+      <div
+        class="filters__operator"
+      >
+        <span>
+          viewFilterContext.where
+        </span>
+         
+        <!---->
+         
+        <!---->
+      </div>
+       
+      <div
+        class="filters__field"
+      >
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         Name
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item active"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item active"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Name
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-             
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+               
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Stars
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Flag
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__type"
-    >
+       
       <div
-        class="dropdown dropdown--floating dropdown--tiny"
+        class="filters__type"
       >
-        <a
-          class="dropdown__selected"
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         viewFilter.is
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item active"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item active"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.is
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.isNot
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.contains
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.containsNot
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.lengthIsLowerThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.isEmpty
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.isNotEmpty
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__value"
-    >
-      <input
-        class="input filters__value-input"
-        type="text"
-      />
-    </div>
-  </div>
-  <div
-    class="filters__item"
-  >
-    <a
-      class="filters__remove"
-    >
-      <i
-        class="fas fa-times"
-      />
-    </a>
-     
-    <div
-      class="filters__operator"
-    >
-      <!---->
        
       <div
-        class="dropdown dropdown--floating dropdown--tiny"
+        class="filters__value"
       >
-        <a
-          class="dropdown__selected"
-        >
-          <!---->
-          
-        viewFilterContext.and
+        <input
+          class="input filters__value-input"
+          type="text"
+        />
+      </div>
+    </div>
+    <div
+      class="filters__item"
+    >
+      <a
+        class="filters__remove"
+      >
+        <i
+          class="fas fa-times"
+        />
+      </a>
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
+      <div
+        class="filters__operator"
+      >
+        <!---->
          
         <div
-          class="dropdown__items hidden"
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-           
-          <ul
-            class="select__items"
+          <a
+            class="dropdown__selected"
           >
-            <li
-              class="select__item active"
+            <!---->
+            
+        viewFilterContext.and
+       
+            <i
+              class="dropdown__toggle-icon fas fa-caret-down"
+            />
+          </a>
+           
+          <div
+            class="dropdown__items hidden"
+          >
+            <!---->
+             
+            <ul
+              class="select__items"
             >
-              <a
-                class="select__item-link"
+              <li
+                class="select__item active"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilterContext.and
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-             
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+               
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilterContext.or
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
+         
+        <!---->
       </div>
        
-      <!---->
-       
-      <!---->
-    </div>
-     
-    <div
-      class="filters__field"
-    >
       <div
-        class="dropdown dropdown--floating dropdown--tiny"
+        class="filters__field"
       >
-        <a
-          class="dropdown__selected"
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         Stars
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Name
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-             
-            <li
-              class="select__item active"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+               
+              <li
+                class="select__item active"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Stars
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Flag
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__type"
-    >
+       
       <div
-        class="dropdown dropdown--floating dropdown--tiny"
+        class="filters__type"
       >
-        <a
-          class="dropdown__selected"
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         viewFilter.is
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item active"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item active"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.is
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.isNot
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.higherThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.lowerThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__value"
-    >
+       
       <div
-        class="filters__value-rating"
+        class="filters__value"
       >
         <div
-          class="rating color--dark-orange editing"
+          class="filters__value-rating"
         >
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star"
-          />
-          <i
-            class="fas rating__star fa-star"
-          />
-          <i
-            class="fas rating__star fa-star"
-          />
+          <div
+            class="rating color--dark-orange editing"
+          >
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star"
+            />
+            <i
+              class="fas rating__star fa-star"
+            />
+            <i
+              class="fas rating__star fa-star"
+            />
+          </div>
         </div>
       </div>
     </div>
@@ -724,292 +700,270 @@ exports[`ViewFilterForm component Full view filter component 1`] = `
 
 exports[`ViewFilterForm component Test rating filter 1`] = `
 <div>
-  <div
-    style="display: none;"
-  >
-    <div
-      class="filters__none"
-    >
-      <div
-        class="filters__none-title"
-      >
-        
-        viewFilterContext.noFilterTitle
-      
-      </div>
-       
-      <div
-        class="filters__none-description"
-      >
-        
-        viewFilterContext.noFilterText
-      
-      </div>
-    </div>
-  </div>
+  <!---->
    
-  <div
-    class="filters__item"
-  >
-    <a
-      class="filters__remove"
-    >
-      <i
-        class="fas fa-times"
-      />
-    </a>
-     
+  <div>
     <div
-      class="filters__operator"
+      class="filters__item"
     >
-      <span>
-        viewFilterContext.where
-      </span>
-       
-      <!---->
-       
-      <!---->
-       
-      <!---->
-    </div>
-     
-    <div
-      class="filters__field"
-    >
-      <div
-        class="dropdown dropdown--floating dropdown--tiny"
+      <a
+        class="filters__remove"
       >
-        <a
-          class="dropdown__selected"
+        <i
+          class="fas fa-times"
+        />
+      </a>
+       
+      <div
+        class="filters__operator"
+      >
+        <span>
+          viewFilterContext.where
+        </span>
+         
+        <!---->
+         
+        <!---->
+      </div>
+       
+      <div
+        class="filters__field"
+      >
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         Stars
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Name
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-             
-            <li
-              class="select__item active"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+               
+              <li
+                class="select__item active"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Stars
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Flag
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__type"
-    >
+       
       <div
-        class="dropdown dropdown--floating dropdown--tiny"
+        class="filters__type"
       >
-        <a
-          class="dropdown__selected"
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         viewFilter.is
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items"
           >
-            <li
-              class="select__item active hover"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item active hover"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.is
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.isNot
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.higherThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.lowerThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__value"
-    >
+       
       <div
-        class="filters__value-rating"
+        class="filters__value"
       >
         <div
-          class="rating color--dark-orange editing"
+          class="filters__value-rating"
         >
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star"
-          />
-          <i
-            class="fas rating__star fa-star"
-          />
-          <i
-            class="fas rating__star fa-star"
-          />
+          <div
+            class="rating color--dark-orange editing"
+          >
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star"
+            />
+            <i
+              class="fas rating__star fa-star"
+            />
+            <i
+              class="fas rating__star fa-star"
+            />
+          </div>
         </div>
       </div>
     </div>
@@ -1041,292 +995,270 @@ exports[`ViewFilterForm component Test rating filter 1`] = `
 
 exports[`ViewFilterForm component Test rating filter 2`] = `
 <div>
-  <div
-    style="display: none;"
-  >
-    <div
-      class="filters__none"
-    >
-      <div
-        class="filters__none-title"
-      >
-        
-        viewFilterContext.noFilterTitle
-      
-      </div>
-       
-      <div
-        class="filters__none-description"
-      >
-        
-        viewFilterContext.noFilterText
-      
-      </div>
-    </div>
-  </div>
+  <!---->
    
-  <div
-    class="filters__item"
-  >
-    <a
-      class="filters__remove"
-    >
-      <i
-        class="fas fa-times"
-      />
-    </a>
-     
+  <div>
     <div
-      class="filters__operator"
+      class="filters__item"
     >
-      <span>
-        viewFilterContext.where
-      </span>
-       
-      <!---->
-       
-      <!---->
-       
-      <!---->
-    </div>
-     
-    <div
-      class="filters__field"
-    >
-      <div
-        class="dropdown dropdown--floating dropdown--tiny"
+      <a
+        class="filters__remove"
       >
-        <a
-          class="dropdown__selected"
+        <i
+          class="fas fa-times"
+        />
+      </a>
+       
+      <div
+        class="filters__operator"
+      >
+        <span>
+          viewFilterContext.where
+        </span>
+         
+        <!---->
+         
+        <!---->
+      </div>
+       
+      <div
+        class="filters__field"
+      >
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         Stars
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Name
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-             
-            <li
-              class="select__item active"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+               
+              <li
+                class="select__item active"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Stars
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         Flag
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__type"
-    >
+       
       <div
-        class="dropdown dropdown--floating dropdown--tiny"
+        class="filters__type"
       >
-        <a
-          class="dropdown__selected"
+        <div
+          class="dropdown dropdown--floating dropdown--tiny"
         >
-          <!---->
-          
+          <a
+            class="dropdown__selected"
+          >
+            <!---->
+            
         viewFilter.is
        
-          <i
-            class="dropdown__toggle-icon fas fa-caret-down"
-          />
-        </a>
-         
-        <div
-          class="dropdown__items hidden"
-        >
-          <div
-            class="select__search"
-          >
             <i
-              class="select__search-icon fas fa-search"
+              class="dropdown__toggle-icon fas fa-caret-down"
             />
-             
-            <input
-              class="select__search-input"
-              placeholder="action.search"
-              type="text"
-            />
-          </div>
+          </a>
            
-          <ul
-            class="select__items"
+          <div
+            class="dropdown__items hidden"
           >
-            <li
-              class="select__item active hover"
+            <div
+              class="select__search"
             >
-              <a
-                class="select__item-link"
+              <i
+                class="select__search-icon fas fa-search"
+              />
+               
+              <input
+                class="select__search-input"
+                placeholder="action.search"
+                type="text"
+              />
+            </div>
+             
+            <ul
+              class="select__items"
+            >
+              <li
+                class="select__item active hover"
               >
-                <div
-                  class="select__item-name"
+                <a
+                  class="select__item-link"
                 >
-                  <!---->
-                  
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.is
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.isNot
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.higherThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-            <li
-              class="select__item"
-            >
-              <a
-                class="select__item-link"
-              >
-                <div
-                  class="select__item-name"
-                >
+                  </div>
+                   
                   <!---->
-                  
+                </a>
+              </li>
+              <li
+                class="select__item"
+              >
+                <a
+                  class="select__item-link"
+                >
+                  <div
+                    class="select__item-name"
+                  >
+                    <!---->
+                    
         viewFilter.lowerThan
       
-                </div>
-                 
-                <!---->
-              </a>
-            </li>
-          </ul>
+                  </div>
+                   
+                  <!---->
+                </a>
+              </li>
+            </ul>
+          </div>
         </div>
       </div>
-    </div>
-     
-    <div
-      class="filters__value"
-    >
+       
       <div
-        class="filters__value-rating"
+        class="filters__value"
       >
         <div
-          class="rating color--dark-orange editing"
+          class="filters__value-rating"
         >
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
-          <i
-            class="fas rating__star fa-star rating__star--selected"
-          />
+          <div
+            class="rating color--dark-orange editing"
+          >
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+            <i
+              class="fas rating__star fa-star rating__star--selected"
+            />
+          </div>
         </div>
       </div>
     </div>
diff --git a/web-frontend/test/unit/database/components/view/viewFilterForm.spec.js b/web-frontend/test/unit/database/components/view/viewFilterForm.spec.js
index e127a8f6f..ebf85636e 100644
--- a/web-frontend/test/unit/database/components/view/viewFilterForm.spec.js
+++ b/web-frontend/test/unit/database/components/view/viewFilterForm.spec.js
@@ -93,7 +93,7 @@ describe('ViewFilterForm component', () => {
     props = {
       primary: {},
       fields: [],
-      view: { filters: {}, _: {} },
+      view: { filters: [], _: {} },
       readOnly: false,
     },
     listeners = {}