Skip to content

Commit

Permalink
Merge branch 'master' into chore/pd/longer-tio
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldambra authored Jan 1, 2025
2 parents e0db5d3 + 3aa25f3 commit eadc1a8
Show file tree
Hide file tree
Showing 175 changed files with 4,193 additions and 1,397 deletions.
1 change: 1 addition & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ services:
extends:
file: docker-compose.base.yml
service: clickhouse
hostname: clickhouse
ports:
- '8123:8123'
- '8443:8443'
Expand Down
3 changes: 1 addition & 2 deletions ee/billing/quota_limiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,11 @@ def sync_org_quota_limits(organization: Organization):
remove_limited_team_tokens(resource, team_attributes, QuotaLimitingCaches.QUOTA_LIMITING_SUSPENDED_KEY)


def get_team_attribute_by_quota_resource(organization: Organization):
def get_team_attribute_by_quota_resource(organization: Organization) -> list[str]:
team_tokens: list[str] = [x for x in list(organization.teams.values_list("api_token", flat=True)) if x]

if not team_tokens:
capture_exception(Exception(f"quota_limiting: No team tokens found for organization: {organization.id}"))
return

return team_tokens

Expand Down
26 changes: 26 additions & 0 deletions ee/billing/test/test_quota_limiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
update_all_org_billing_quotas,
)
from posthog.api.test.test_team import create_team
from posthog.models.team.team import Team
from posthog.redis import get_client
from posthog.test.base import BaseTest, _create_event

Expand Down Expand Up @@ -759,3 +760,28 @@ def test_sync_org_quota_limits(self):
assert sorted(
list_limited_team_attributes(QuotaResource.ROWS_SYNCED, QuotaLimitingCaches.QUOTA_LIMITER_CACHE_KEY)
) == sorted(["1337"])

@patch("ee.billing.quota_limiting.capture_exception")
def test_get_team_attribute_by_quota_resource(self, mock_capture):
Team.objects.all().delete()

team1 = Team.objects.create(organization=self.organization, api_token="token1")
team2 = Team.objects.create(organization=self.organization, api_token="token2")

tokens = get_team_attribute_by_quota_resource(self.organization)

self.assertEqual(set(tokens), {"token1", "token2"})

team1.delete()
team2.delete()

Team.objects.create(organization=self.organization, api_token="")

tokens = get_team_attribute_by_quota_resource(self.organization)

self.assertEqual(tokens, [])
mock_capture.assert_called_once()
self.assertIn(
f"quota_limiting: No team tokens found for organization: {self.organization.id}",
str(mock_capture.call_args[0][0]),
)
17 changes: 11 additions & 6 deletions ee/clickhouse/views/experiment_saved_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
from posthog.api.routing import TeamAndOrgViewSetMixin
from posthog.api.shared import UserBasicSerializer
from posthog.models.experiment import ExperimentSavedMetric, ExperimentToSavedMetric
from posthog.schema import FunnelsQuery, TrendsQuery
from posthog.schema import ExperimentFunnelsQuery, ExperimentTrendsQuery


class ExperimentToSavedMetricSerializer(serializers.ModelSerializer):
query = serializers.JSONField(source="saved_metric.query", read_only=True)
name = serializers.CharField(source="saved_metric.name", read_only=True)

class Meta:
model = ExperimentToSavedMetric
fields = [
Expand All @@ -18,6 +21,8 @@ class Meta:
"saved_metric",
"metadata",
"created_at",
"query",
"name",
]
read_only_fields = [
"id",
Expand Down Expand Up @@ -52,15 +57,15 @@ def validate_query(self, value):

metric_query = value

if metric_query.get("kind") not in ["TrendsQuery", "FunnelsQuery"]:
raise ValidationError("Metric query kind must be 'TrendsQuery' or 'FunnelsQuery'")
if metric_query.get("kind") not in ["ExperimentTrendsQuery", "ExperimentFunnelsQuery"]:
raise ValidationError("Metric query kind must be 'ExperimentTrendsQuery' or 'ExperimentFunnelsQuery'")

# pydantic models are used to validate the query
try:
if metric_query["kind"] == "TrendsQuery":
TrendsQuery(**metric_query)
if metric_query["kind"] == "ExperimentTrendsQuery":
ExperimentTrendsQuery(**metric_query)
else:
FunnelsQuery(**metric_query)
ExperimentFunnelsQuery(**metric_query)
except pydantic.ValidationError as e:
raise ValidationError(str(e.errors())) from e

Expand Down
4 changes: 1 addition & 3 deletions ee/clickhouse/views/experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,7 @@ class ExperimentSerializer(serializers.ModelSerializer):
queryset=ExperimentHoldout.objects.all(), source="holdout", required=False, allow_null=True
)
saved_metrics = ExperimentToSavedMetricSerializer(many=True, source="experimenttosavedmetric_set", read_only=True)
saved_metrics_ids = serializers.ListField(
child=serializers.JSONField(), write_only=True, required=False, allow_null=True
)
saved_metrics_ids = serializers.ListField(child=serializers.JSONField(), required=False, allow_null=True)

class Meta:
model = Experiment
Expand Down
29 changes: 24 additions & 5 deletions ee/clickhouse/views/test/test_clickhouse_experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,13 @@ def test_saved_metrics(self):
{
"name": "Test Experiment saved metric",
"description": "Test description",
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {
"kind": "TrendsQuery",
"series": [{"kind": "EventsNode", "event": "$pageview"}],
},
},
},
)

Expand All @@ -380,7 +386,10 @@ def test_saved_metrics(self):
self.assertEqual(response.json()["description"], "Test description")
self.assertEqual(
response.json()["query"],
{"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
{
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
)
self.assertEqual(response.json()["created_by"]["id"], self.user.pk)

Expand Down Expand Up @@ -418,7 +427,11 @@ def test_saved_metrics(self):
saved_metric = Experiment.objects.get(pk=exp_id).saved_metrics.first()
self.assertEqual(saved_metric.id, saved_metric_id)
self.assertEqual(
saved_metric.query, {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]}
saved_metric.query,
{
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
)

# Now try updating experiment with new saved metric
Expand All @@ -427,7 +440,10 @@ def test_saved_metrics(self):
{
"name": "Test Experiment saved metric 2",
"description": "Test description 2",
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
},
},
)

Expand Down Expand Up @@ -513,7 +529,10 @@ def test_validate_saved_metrics_payload(self):
{
"name": "Test Experiment saved metric",
"description": "Test description",
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
},
)

Expand Down
63 changes: 48 additions & 15 deletions ee/clickhouse/views/test/test_experiment_saved_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ def test_validation_of_query_metric(self):
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json()["detail"], "Metric query kind must be 'TrendsQuery' or 'FunnelsQuery'")
self.assertEqual(
response.json()["detail"], "Metric query kind must be 'ExperimentTrendsQuery' or 'ExperimentFunnelsQuery'"
)

response = self.client.post(
f"/api/projects/{self.team.id}/experiment_saved_metrics/",
Expand All @@ -47,40 +49,46 @@ def test_validation_of_query_metric(self):
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json()["detail"], "Metric query kind must be 'TrendsQuery' or 'FunnelsQuery'")
self.assertEqual(
response.json()["detail"], "Metric query kind must be 'ExperimentTrendsQuery' or 'ExperimentFunnelsQuery'"
)

response = self.client.post(
f"/api/projects/{self.team.id}/experiment_saved_metrics/",
data={
"name": "Test Experiment saved metric",
"description": "Test description",
"query": {"kind": "ExperimentTrendsQuery"},
"query": {"kind": "TrendsQuery"},
},
format="json",
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json()["detail"], "Metric query kind must be 'TrendsQuery' or 'FunnelsQuery'")
self.assertEqual(
response.json()["detail"], "Metric query kind must be 'ExperimentTrendsQuery' or 'ExperimentFunnelsQuery'"
)

response = self.client.post(
f"/api/projects/{self.team.id}/experiment_saved_metrics/",
data={
"name": "Test Experiment saved metric",
"description": "Test description",
"query": {"kind": "TrendsQuery"},
"query": {"kind": "ExperimentTrendsQuery"},
},
format="json",
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertTrue("'loc': ('series',), 'msg': 'Field required'" in response.json()["detail"])
self.assertTrue("'loc': ('count_query',), 'msg': 'Field required'" in response.json()["detail"])

response = self.client.post(
f"/api/projects/{self.team.id}/experiment_saved_metrics/",
data={
"name": "Test Experiment saved metric",
"description": "Test description",
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
},
format="json",
)
Expand All @@ -93,7 +101,13 @@ def test_create_update_experiment_saved_metrics(self) -> None:
data={
"name": "Test Experiment saved metric",
"description": "Test description",
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {
"kind": "TrendsQuery",
"series": [{"kind": "EventsNode", "event": "$pageview"}],
},
},
},
format="json",
)
Expand All @@ -104,7 +118,10 @@ def test_create_update_experiment_saved_metrics(self) -> None:
self.assertEqual(response.json()["description"], "Test description")
self.assertEqual(
response.json()["query"],
{"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
{
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
)
self.assertEqual(response.json()["created_by"]["id"], self.user.pk)

Expand Down Expand Up @@ -142,7 +159,11 @@ def test_create_update_experiment_saved_metrics(self) -> None:
saved_metric = Experiment.objects.get(pk=exp_id).saved_metrics.first()
self.assertEqual(saved_metric.id, saved_metric_id)
self.assertEqual(
saved_metric.query, {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]}
saved_metric.query,
{
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
)

# Now try updating saved metric
Expand All @@ -151,15 +172,21 @@ def test_create_update_experiment_saved_metrics(self) -> None:
{
"name": "Test Experiment saved metric 2",
"description": "Test description 2",
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
},
},
)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.json()["name"], "Test Experiment saved metric 2")
self.assertEqual(
response.json()["query"],
{"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
{
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
},
)

# make sure experiment in question was updated as well
Expand All @@ -168,7 +195,10 @@ def test_create_update_experiment_saved_metrics(self) -> None:
self.assertEqual(saved_metric.id, saved_metric_id)
self.assertEqual(
saved_metric.query,
{"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
{
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageleave"}]},
},
)
self.assertEqual(saved_metric.name, "Test Experiment saved metric 2")
self.assertEqual(saved_metric.description, "Test description 2")
Expand All @@ -186,7 +216,10 @@ def test_invalid_create(self):
f"/api/projects/{self.team.id}/experiment_saved_metrics/",
data={
"name": None, # invalid
"query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
"query": {
"kind": "ExperimentTrendsQuery",
"count_query": {"kind": "TrendsQuery", "series": [{"kind": "EventsNode", "event": "$pageview"}]},
},
},
format="json",
)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 0 additions & 8 deletions frontend/src/layout/navigation-3000/navigationLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -530,14 +530,6 @@ export const navigation3000Logic = kea<navigation3000LogicType>([
logic: editorSidebarLogic,
}
: null,
featureFlags[FEATURE_FLAGS.DATA_MODELING] && hasOnboardedAnyProduct
? {
identifier: Scene.DataModel,
label: 'Data model',
icon: <IconServer />,
to: isUsingSidebar ? undefined : urls.dataModel(),
}
: null,
hasOnboardedAnyProduct
? {
identifier: Scene.Pipeline,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { ActivityScope, AvailableFeature } from '~/types'

import { SidePanelPaneHeader } from '../../components/SidePanelPaneHeader'
import { SidePanelActivityMetalytics } from './SidePanelActivityMetalytics'
import { SidePanelActivitySubscriptions } from './SidePanelActivitySubscriptions'

const SCROLL_TRIGGER_OFFSET = 100

Expand Down Expand Up @@ -152,6 +153,14 @@ export const SidePanelActivity = (): JSX.Element => {
},
]
: []),
...(featureFlags[FEATURE_FLAGS.CDP_ACTIVITY_LOG_NOTIFICATIONS]
? [
{
key: SidePanelActivityTab.Subscriptions,
label: 'Subscriptions',
},
]
: []),
]}
/>
</div>
Expand Down Expand Up @@ -280,6 +289,8 @@ export const SidePanelActivity = (): JSX.Element => {
</>
) : activeTab === SidePanelActivityTab.Metalytics ? (
<SidePanelActivityMetalytics />
) : activeTab === SidePanelActivityTab.Subscriptions ? (
<SidePanelActivitySubscriptions />
) : null}
</ScrollableShadows>
</div>
Expand Down
Loading

0 comments on commit eadc1a8

Please sign in to comment.