Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/features/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from .feature_segments.serializers import (
CustomCreateSegmentOverrideFeatureSegmentSerializer,
)
from .feature_types import FEATURE_TYPE_CHOICES
from .models import Feature, FeatureState
from .multivariate.serializers import NestedMultivariateFeatureOptionSerializer

Expand Down Expand Up @@ -95,6 +96,11 @@ class FeatureQuerySerializer(serializers.Serializer): # type: ignore[type-arg]
)

is_archived = serializers.BooleanField(required=False)
type = serializers.ChoiceField(
choices=FEATURE_TYPE_CHOICES,
required=False,
help_text="Feature type to filter on (STANDARD or MULTIVARIATE).",
)
environment = serializers.IntegerField(
required=False,
help_text="Integer ID of the environment to view features in the context of.",
Expand Down
3 changes: 3 additions & 0 deletions api/features/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,9 @@ def _filter_queryset(
if "is_archived" in query_serializer.initial_data:
queryset = queryset.filter(is_archived=query_data["is_archived"])

if query_data.get("type"):
queryset = queryset.filter(type=query_data["type"])

queryset = self.filter_owners_and_group_owners(queryset, query_data)

return queryset
Expand Down
37 changes: 37 additions & 0 deletions api/tests/integration/features/test_integration_features.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json

import pytest
from django.urls import reverse
from rest_framework import status

Expand Down Expand Up @@ -203,3 +204,39 @@ def test_list_features__filter_by_archived_status__returns_matching_features( #
list_features_is_archived_true_response.json()["results"][0]["id"]
== archived_feature_id
)


@pytest.mark.parametrize(
"type_filter, expected_feature_name",
[
("STANDARD", "standard_feature"),
("MULTIVARIATE", "multivariate_feature"),
],
)
def test_list_features__filter_by_type__returns_matching_features( # type: ignore[no-untyped-def]
admin_client, project, type_filter, expected_feature_name
):
# Given
features_url = reverse("api-v1:projects:project-features-list", args=[project])
admin_client.post(
features_url,
data={"name": "standard_feature", "project": project},
)
admin_client.post(
features_url,
data={
"name": "multivariate_feature",
"project": project,
"type": "MULTIVARIATE",
"initial_value": "control",
},
)

# When
response = admin_client.get(f"{features_url}?type={type_filter}")

# Then
assert response.status_code == status.HTTP_200_OK
response_json = response.json()
assert response_json["count"] == 1
assert response_json["results"][0]["name"] == expected_feature_name