diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index c5f026f5f1363..58b1f59bb3dfe 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -98,6 +98,7 @@ import { SessionRecordingSnapshotParams, SessionRecordingSnapshotResponse, SessionRecordingType, + SessionRecordingUpdateType, SharingConfigurationType, SlackChannelType, SubscriptionType, @@ -1805,6 +1806,12 @@ const api = { ): Promise { return await new ApiRequest().recording(recordingId).withQueryString(toParams(params)).get() }, + async update( + recordingId: SessionRecordingType['id'], + data: Partial + ): Promise { + return await new ApiRequest().recording(recordingId).update({ data }) + }, async persist(recordingId: SessionRecordingType['id']): Promise<{ success: boolean }> { return await new ApiRequest().recording(recordingId).withAction('persist').create() diff --git a/frontend/src/lib/utils/eventUsageLogic.ts b/frontend/src/lib/utils/eventUsageLogic.ts index 108c4dc629fd0..30dc587df6482 100644 --- a/frontend/src/lib/utils/eventUsageLogic.ts +++ b/frontend/src/lib/utils/eventUsageLogic.ts @@ -361,11 +361,6 @@ export const eventUsageLogic = kea([ reportBookmarkletDragged: true, reportProjectCreationSubmitted: (projectCount: number, nameLength: number) => ({ projectCount, nameLength }), reportProjectNoticeDismissed: (key: string) => ({ key }), - reportBulkInviteAttempted: (inviteesCount: number, namesCount: number) => ({ inviteesCount, namesCount }), - reportInviteAttempted: (nameProvided: boolean, instanceEmailAvailable: boolean) => ({ - nameProvided, - instanceEmailAvailable, - }), reportPersonPropertyUpdated: ( action: 'added' | 'updated' | 'removed', totalProperties: number, @@ -572,9 +567,6 @@ export const eventUsageLogic = kea([ }), reportSurveyCreated: (survey: Survey, isDuplicate?: boolean) => ({ survey, isDuplicate }), reportSurveyEdited: (survey: Survey) => ({ survey }), - reportSurveyLaunched: (survey: Survey) => ({ survey }), - reportSurveyStopped: (survey: Survey) => ({ survey }), - reportSurveyResumed: (survey: Survey) => ({ survey }), reportSurveyArchived: (survey: Survey) => ({ survey }), reportSurveyTemplateClicked: (template: SurveyTemplateType) => ({ template }), reportSurveyCycleDetected: (survey: Survey | NewSurvey) => ({ survey }), @@ -741,26 +733,6 @@ export const eventUsageLogic = kea([ // ProjectNotice was previously called DemoWarning posthog.capture('demo warning dismissed', { warning_key: key }) }, - reportBulkInviteAttempted: async ({ - inviteesCount, - namesCount, - }: { - inviteesCount: number - namesCount: number - }) => { - // namesCount -> Number of invitees for which a name was provided - posthog.capture('bulk invite attempted', { invitees_count: inviteesCount, name_count: namesCount }) - for (let i = 0; i < inviteesCount; i++) { - posthog.capture('team member invited') - } - }, - reportInviteAttempted: async ({ nameProvided, instanceEmailAvailable }) => { - posthog.capture('team member invited') - posthog.capture('team invite attempted', { - name_provided: nameProvided, - instance_email_available: instanceEmailAvailable, - }) - }, reportFunnelCalculated: async ({ eventCount, actionCount, interval, funnelVizType, success, error }) => { posthog.capture('funnel result calculated', { event_count: eventCount, @@ -1268,16 +1240,6 @@ export const eventUsageLogic = kea([ ), }) }, - reportSurveyLaunched: ({ survey }) => { - posthog.capture('survey launched', { - name: survey.name, - id: survey.id, - survey_type: survey.type, - question_types: survey.questions.map((question) => question.type), - created_at: survey.created_at, - start_date: survey.start_date, - }) - }, reportSurveyViewed: ({ survey }) => { posthog.capture('survey viewed', { name: survey.name, @@ -1287,23 +1249,6 @@ export const eventUsageLogic = kea([ end_date: survey.end_date, }) }, - reportSurveyStopped: ({ survey }) => { - posthog.capture('survey stopped', { - name: survey.name, - id: survey.id, - created_at: survey.created_at, - start_date: survey.start_date, - end_date: survey.end_date, - }) - }, - reportSurveyResumed: ({ survey }) => { - posthog.capture('survey resumed', { - name: survey.name, - id: survey.id, - created_at: survey.created_at, - start_date: survey.start_date, - }) - }, reportSurveyArchived: ({ survey }) => { posthog.capture('survey archived', { name: survey.name, diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 25ab04b3a36df..380cf3d17a64a 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -9386,6 +9386,9 @@ "type": "string" }, "type": "array" + }, + "user_modified_filters": { + "type": "object" } }, "required": ["kind", "order"], diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 8a97b7421d213..2507937119b48 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -322,6 +322,7 @@ export interface RecordingsQuery extends DataNode { | 'mouse_activity_count' limit?: integer offset?: integer + user_modified_filters?: Record } export interface HogQLNotice { diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts index 7a00e7b49b323..d42f36b416a99 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.test.ts @@ -74,6 +74,9 @@ describe('sessionRecordingDataLogic', () => { post: { '/api/projects/:team/query': recordingEventsJson, }, + patch: { + '/api/projects/:team/session_recordings/:id': { success: true }, + }, }) initKeaTests() logic = sessionRecordingDataLogic({ @@ -364,7 +367,7 @@ describe('sessionRecordingDataLogic', () => { action.payload.source?.source === 'blob', 'loadSnapshotsForSourceSuccess', // and then we report having viewed the recording - 'reportViewed', + 'markViewed', // the response to the success action triggers loading of the second item which is the realtime source (action) => action.type === logic.actionTypes.loadSnapshotsForSource && diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts index 1def7eb6f8e99..b3f2edb26959d 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingDataLogic.ts @@ -417,13 +417,14 @@ export const sessionRecordingDataLogic = kea([ loadSnapshotsForSource: (source: Pick) => ({ source }), loadEvents: true, loadFullEventData: (event: RecordingEventType) => ({ event }), - reportViewed: true, + markViewed: (delay?: number) => ({ delay }), reportUsageIfFullyLoaded: true, persistRecording: true, maybePersistRecording: true, pollRealtimeSnapshots: true, stopRealtimePolling: true, setTrackedWindow: (windowId: string | null) => ({ windowId }), + setWasMarkedViewed: (wasMarkedViewed: boolean) => ({ wasMarkedViewed }), }), reducers(() => ({ trackedWindow: [ @@ -466,6 +467,12 @@ export const sessionRecordingDataLogic = kea([ }, }, ], + wasMarkedViewed: [ + false as boolean, + { + setWasMarkedViewed: (_, { wasMarkedViewed }) => wasMarkedViewed, + }, + ], })), loaders(({ values, props, cache }) => ({ sessionPlayerMetaData: { @@ -476,9 +483,7 @@ export const sessionRecordingDataLogic = kea([ cache.metaStartTime = performance.now() - const response = await api.recordings.get(props.sessionRecordingId, { - save_view: true, - }) + const response = await api.recordings.get(props.sessionRecordingId) breakpoint() return response @@ -750,7 +755,9 @@ export const sessionRecordingDataLogic = kea([ }) } else if (!cache.firstPaintDuration) { cache.firstPaintDuration = Math.round(performance.now() - cache.snapshotsStartTime) - actions.reportViewed() + } + if (!values.wasMarkedViewed) { + actions.markViewed() } actions.loadNextSnapshotSource() @@ -815,25 +822,27 @@ export const sessionRecordingDataLogic = kea([ resetTimingsCache(cache) } }, - reportViewed: async (_, breakpoint) => { + markViewed: async ({ delay }, breakpoint) => { const durations = generateRecordingReportDurations(cache) - breakpoint() // Triggered on first paint - eventUsageLogic.actions.reportRecording( - values.sessionPlayerData, + breakpoint() + if (values.wasMarkedViewed) { + return + } + actions.setWasMarkedViewed(true) // this prevents us from calling the function multiple times + + await breakpoint(IS_TEST_MODE ? 1 : delay ?? 3000) + await api.recordings.update(props.sessionRecordingId, { + viewed: true, + player_metadata: values.sessionPlayerMetaData, durations, - SessionRecordingUsageType.VIEWED, - values.sessionPlayerMetaData, - 0 - ) + }) await breakpoint(IS_TEST_MODE ? 1 : 10000) - eventUsageLogic.actions.reportRecording( - values.sessionPlayerData, + await api.recordings.update(props.sessionRecordingId, { + analyzed: true, + player_metadata: values.sessionPlayerMetaData, durations, - SessionRecordingUsageType.ANALYZED, - values.sessionPlayerMetaData, - 10 - ) + }) }, maybePersistRecording: () => { diff --git a/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts b/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts index 180b6945a35f6..56240e7ec1ee0 100644 --- a/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts +++ b/frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts @@ -112,6 +112,7 @@ export const sessionRecordingPlayerLogic = kea( 'createExportJSON', 'customRRWebEvents', 'fullyLoaded', + 'wasMarkedViewed', ], playerSettingsLogic, ['speed', 'skipInactivitySetting', 'showMouseTail'], @@ -131,6 +132,8 @@ export const sessionRecordingPlayerLogic = kea( 'loadSnapshotSourcesFailure', 'loadRecordingMetaSuccess', 'maybePersistRecording', + 'setWasMarkedViewed', + 'markViewed', ], playerSettingsLogic, ['setSpeed', 'setSkipInactivitySetting'], @@ -812,6 +815,10 @@ export const sessionRecordingPlayerLogic = kea( setEndReached: ({ reached }) => { if (reached) { actions.setPause() + // TODO: this will be time-gated so won't happen immediately, but we need it to + if (!values.wasMarkedViewed) { + actions.markViewed(0) + } } }, startBuffer: () => { diff --git a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts index aa36edf0d08d2..946e9579f07cd 100644 --- a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts +++ b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts @@ -16,7 +16,6 @@ import { FEATURE_FLAGS } from 'lib/constants' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { objectClean, objectsEqual } from 'lib/utils' import { eventUsageLogic } from 'lib/utils/eventUsageLogic' -import posthog from 'posthog-js' import { NodeKind, RecordingsQuery, RecordingsQueryResponse } from '~/queries/schema' import { @@ -95,19 +94,6 @@ export const getDefaultFilters = (personUUID?: PersonUUID): RecordingUniversalFi return personUUID ? DEFAULT_PERSON_RECORDING_FILTERS : DEFAULT_RECORDING_FILTERS } -const capturePartialFilters = (filters: Partial): void => { - // capture only the partial filters applied (not the full filters object) - // take each key from the filter and change it to `partial_filter_chosen_${key}` - const partialFilters = Object.keys(filters).reduce((acc, key) => { - acc[`partial_filter_chosen_${key}`] = filters[key] - return acc - }, {}) - - posthog.capture('recording list filters changed', { - ...partialFilters, - }) -} - export function convertUniversalFiltersToRecordingsQuery(universalFilters: RecordingUniversalFilters): RecordingsQuery { const filters = filtersFromUniversalFilterGroups(universalFilters) @@ -298,7 +284,10 @@ export const sessionRecordingsPlaylistLogic = kea ({ direction }), + loadSessionRecordings: (direction?: 'newer' | 'older', userModifiedFilters?: Record) => ({ + direction, + userModifiedFilters, + }), maybeLoadSessionRecordings: (direction?: 'newer' | 'older') => ({ direction }), loadNext: true, loadPrev: true, @@ -340,7 +329,7 @@ export const sessionRecordingsPlaylistLogic = kea { + loadSessionRecordings: async ({ direction, userModifiedFilters }, breakpoint) => { const params: RecordingsQuery = { ...convertUniversalFiltersToRecordingsQuery(values.filters), person_uuid: props.personUUID ?? '', @@ -348,6 +337,10 @@ export const sessionRecordingsPlaylistLogic = kea { - actions.loadSessionRecordings() + actions.loadSessionRecordings(undefined, filters) props.onFiltersChange?.(values.filters) - capturePartialFilters(filters) actions.loadEventsHaveSessionId() }, diff --git a/frontend/src/scenes/settings/organization/inviteLogic.ts b/frontend/src/scenes/settings/organization/inviteLogic.ts index bf1a9eb8c6d5a..878961f7332bf 100644 --- a/frontend/src/scenes/settings/organization/inviteLogic.ts +++ b/frontend/src/scenes/settings/organization/inviteLogic.ts @@ -4,7 +4,6 @@ import { router, urlToAction } from 'kea-router' import api from 'lib/api' import { OrganizationMembershipLevel } from 'lib/constants' import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast' -import { eventUsageLogic } from 'lib/utils/eventUsageLogic' import { organizationLogic } from 'scenes/organizationLogic' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' @@ -55,10 +54,6 @@ export const inviteLogic = kea([ const payload: Pick[] = values.invitesToSend.filter((invite) => invite.target_email) - eventUsageLogic.actions.reportBulkInviteAttempted( - payload.length, - payload.filter((invite) => !!invite.first_name).length - ) if (values.message) { payload.forEach((payload) => (payload.message = values.message)) } diff --git a/frontend/src/scenes/surveys/surveyLogic.tsx b/frontend/src/scenes/surveys/surveyLogic.tsx index a2fd70b7b1acc..a9a1262656e2b 100644 --- a/frontend/src/scenes/surveys/surveyLogic.tsx +++ b/frontend/src/scenes/surveys/surveyLogic.tsx @@ -132,11 +132,8 @@ export const surveyLogic = kea([ eventUsageLogic, [ 'reportSurveyCreated', - 'reportSurveyLaunched', 'reportSurveyEdited', 'reportSurveyArchived', - 'reportSurveyStopped', - 'reportSurveyResumed', 'reportSurveyViewed', 'reportSurveyCycleDetected', ], @@ -578,15 +575,12 @@ export const surveyLogic = kea([ launchSurveySuccess: ({ survey }) => { lemonToast.success(<>Survey {survey.name} launched) actions.loadSurveys() - actions.reportSurveyLaunched(survey) }, - stopSurveySuccess: ({ survey }) => { + stopSurveySuccess: () => { actions.loadSurveys() - actions.reportSurveyStopped(survey) }, - resumeSurveySuccess: ({ survey }) => { + resumeSurveySuccess: () => { actions.loadSurveys() - actions.reportSurveyResumed(survey) }, archiveSurvey: () => { actions.updateSurvey({ archived: true }) diff --git a/frontend/src/types.ts b/frontend/src/types.ts index ae3c0d3c9aebe..f4b10ce345206 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -1404,6 +1404,13 @@ export interface SessionRecordingType { ongoing?: boolean } +export interface SessionRecordingUpdateType { + viewed?: boolean + analyzed?: boolean + player_metadata?: Record | null + durations?: Record | null +} + export interface SessionRecordingPropertiesType { id: string properties?: Record diff --git a/posthog/api/dashboards/dashboard.py b/posthog/api/dashboards/dashboard.py index 5a15fe513a008..86c2c568e9340 100644 --- a/posthog/api/dashboards/dashboard.py +++ b/posthog/api/dashboards/dashboard.py @@ -174,6 +174,8 @@ def create(self, validated_data: dict, *args: Any, **kwargs: Any) -> Dashboard: validated_data.pop("delete_insights", None) # not used during creation validated_data = self._update_creation_mode(validated_data, use_template, use_dashboard) tags = validated_data.pop("tags", None) # tags are created separately below as global tag relationships + current_url = request.headers.get("Referer") + session_id = request.headers.get("X-Posthog-Session-Id") request_filters = request.data.get("filters") if request_filters: @@ -226,6 +228,8 @@ def create(self, validated_data: dict, *args: Any, **kwargs: Any) -> Dashboard: "template_key": use_template, "duplicated": bool(use_dashboard), "dashboard_id": use_dashboard, + "$current_url": current_url, + "$session_id": session_id, }, ) @@ -510,6 +514,8 @@ def move_tile(self, request: Request, *args: Any, **kwargs: Any) -> Response: parser_classes=[DashboardTemplateCreationJSONSchemaParser], ) def create_from_template_json(self, request: Request, *args: Any, **kwargs: Any) -> Response: + current_url = request.headers.get("Referer") + session_id = request.headers.get("X-Posthog-Session-Id") dashboard = Dashboard.objects.create( team_id=self.team_id, created_by=cast(User, request.user), @@ -530,6 +536,8 @@ def create_from_template_json(self, request: Request, *args: Any, **kwargs: Any) "duplicated": False, "dashboard_id": dashboard.pk, "creation_context": creation_context, + "$current_url": current_url, + "$session_id": session_id, }, ) except Exception: diff --git a/posthog/api/insight.py b/posthog/api/insight.py index 793edcb105e15..1efbc0a74a538 100644 --- a/posthog/api/insight.py +++ b/posthog/api/insight.py @@ -2,6 +2,7 @@ from functools import lru_cache from typing import Any, Optional, Union, cast +import posthoganalytics import structlog from django.db import transaction from django.db.models import Count, Prefetch, QuerySet @@ -15,13 +16,12 @@ from loginas.utils import is_impersonated_session from prometheus_client import Counter from rest_framework import request, serializers, status, viewsets -from posthog.api.utils import action from rest_framework.exceptions import ParseError, PermissionDenied, ValidationError from rest_framework.parsers import JSONParser +from rest_framework.request import Request from rest_framework.response import Response from rest_framework.settings import api_settings from rest_framework_csv import renderers as csvrenderers -from rest_framework.request import Request from posthog import schema from posthog.api.documentation import extend_schema @@ -32,14 +32,13 @@ TrendResultsSerializer, TrendSerializer, ) +from posthog.api.monitoring import Feature, monitor from posthog.api.routing import TeamAndOrgViewSetMixin from posthog.api.shared import UserBasicSerializer from posthog.api.tagged_item import TaggedItemSerializerMixin, TaggedItemViewSetMixin -from posthog.api.utils import format_paginated_url +from posthog.api.utils import action, format_paginated_url from posthog.auth import SharingAccessTokenAuthentication -from posthog.caching.fetch_from_cache import ( - InsightResult, -) +from posthog.caching.fetch_from_cache import InsightResult from posthog.clickhouse.cancel import cancel_query_on_cluster from posthog.constants import ( INSIGHT, @@ -51,13 +50,17 @@ FunnelVizType, ) from posthog.decorators import cached_by_filters +from posthog.event_usage import groups from posthog.helpers.multi_property_breakdown import ( protect_old_clients_from_multi_property_default, ) from posthog.hogql.constants import BREAKDOWN_VALUES_LIMIT from posthog.hogql.errors import ExposedHogQLError from posthog.hogql.timings import HogQLTimings -from posthog.hogql_queries.apply_dashboard_filters import WRAPPER_NODE_KINDS +from posthog.hogql_queries.apply_dashboard_filters import ( + WRAPPER_NODE_KINDS, + apply_dashboard_filters_to_dict, +) from posthog.hogql_queries.legacy_compatibility.feature_flag import ( hogql_insights_replace_filters, ) @@ -86,6 +89,8 @@ from posthog.models.filters.path_filter import PathFilter from posthog.models.filters.stickiness_filter import StickinessFilter from posthog.models.insight import InsightViewed +from posthog.models.organization import Organization +from posthog.models.team.team import Team from posthog.models.utils import UUIDT from posthog.queries.funnels import ( ClickhouseFunnelTimeToConvert, @@ -104,14 +109,10 @@ from posthog.settings import CAPTURE_TIME_TO_SEE_DATA, SITE_URL from posthog.user_permissions import UserPermissionsSerializerMixin from posthog.utils import ( + filters_override_requested_by_client, refresh_requested_by_client, relative_date_parse, str_to_bool, - filters_override_requested_by_client, -) -from posthog.api.monitoring import monitor, Feature -from posthog.hogql_queries.apply_dashboard_filters import ( - apply_dashboard_filters_to_dict, ) logger = structlog.get_logger(__name__) @@ -123,7 +124,7 @@ ) -def log_insight_activity( +def log_and_report_insight_activity( *, activity: str, insight: Insight, @@ -134,13 +135,13 @@ def log_insight_activity( user: User, was_impersonated: bool, changes: Optional[list[Change]] = None, + properties: Optional[dict[str, Any]] = None, ) -> None: """ Insight id and short_id are passed separately as some activities (like delete) alter the Insight instance The experiments feature creates insights without a name, this does not log those """ - insight_name: Optional[str] = insight.name if insight.name else insight.derived_name if insight_name: log_activity( @@ -153,6 +154,17 @@ def log_insight_activity( activity=activity, detail=Detail(name=insight_name, changes=changes, short_id=insight_short_id), ) + if properties is None: + properties = {} + organization = Organization.objects.get(id=organization_id) + team = Team.objects.get(id=team_id) + if not was_impersonated and user.distinct_id: + posthoganalytics.capture( + user.distinct_id, + f"insight {activity}", + {"insight_id": insight_short_id, **properties}, + groups=(groups(organization, team) if team_id else groups(organization)), + ) class QuerySchemaParser(JSONParser): @@ -344,6 +356,8 @@ def create(self, validated_data: dict, *args: Any, **kwargs: Any) -> Insight: request = self.context["request"] tags = validated_data.pop("tags", None) # tags are created separately as global tag relationships team_id = self.context["team_id"] + current_url = request.headers.get("Referer") + session_id = request.headers.get("X-Posthog-Session-Id") created_by = validated_data.pop("created_by", request.user) dashboards = validated_data.pop("dashboards", None) @@ -365,7 +379,11 @@ def create(self, validated_data: dict, *args: Any, **kwargs: Any) -> Insight: # Manual tag creation since this create method doesn't call super() self._attempt_set_tags(tags, insight) - log_insight_activity( + properties = {} + properties["$current_url"] = current_url + properties["$session_id"] = session_id + + log_and_report_insight_activity( activity="created", insight=insight, insight_id=insight.id, @@ -374,6 +392,7 @@ def create(self, validated_data: dict, *args: Any, **kwargs: Any) -> Insight: team_id=team_id, user=self.context["request"].user, was_impersonated=is_impersonated_session(self.context["request"]), + properties=properties, ) return insight @@ -381,6 +400,8 @@ def create(self, validated_data: dict, *args: Any, **kwargs: Any) -> Insight: @transaction.atomic() @monitor(feature=Feature.INSIGHT, endpoint="insight", method="PATCH") def update(self, instance: Insight, validated_data: dict, **kwargs) -> Insight: + current_url = self.context["request"].headers.get("Referer") + session_id = self.context["request"].headers.get("X-Posthog-Session-Id") dashboards_before_change: list[Union[str, dict]] = [] try: # since it is possible to be undeleting a soft deleted insight @@ -415,13 +436,20 @@ def update(self, instance: Insight, validated_data: dict, **kwargs) -> Insight: if not are_alerts_supported_for_insight(updated_insight): instance.alertconfiguration_set.all().delete() - self._log_insight_update(before_update, dashboards_before_change, updated_insight) + self._log_insight_update(before_update, dashboards_before_change, updated_insight, current_url, session_id) self.user_permissions.reset_insights_dashboard_cached_results() return updated_insight - def _log_insight_update(self, before_update, dashboards_before_change, updated_insight): + def _log_insight_update( + self, + before_update, + dashboards_before_change, + updated_insight, + current_url, + session_id, + ): """ KLUDGE: Automatic detection of insight dashboard updates is flaky This removes any detected update from the auto-detected changes @@ -435,7 +463,11 @@ def _log_insight_update(self, before_update, dashboards_before_change, updated_i synthetic_dashboard_changes = self._synthetic_dashboard_changes(dashboards_before_change) changes = detected_changes + synthetic_dashboard_changes - log_insight_activity( + properties = {} + properties["$current_url"] = current_url + properties["$session_id"] = session_id + + log_and_report_insight_activity( activity="updated", insight=updated_insight, insight_id=updated_insight.id, @@ -445,6 +477,7 @@ def _log_insight_update(self, before_update, dashboards_before_change, updated_i user=self.context["request"].user, was_impersonated=is_impersonated_session(self.context["request"]), changes=changes, + properties=properties, ) def _synthetic_dashboard_changes(self, dashboards_before_change: list[dict]) -> list[Change]: diff --git a/posthog/api/organization_invite.py b/posthog/api/organization_invite.py index 6acbf00f1b95c..def55f6628c33 100644 --- a/posthog/api/organization_invite.py +++ b/posthog/api/organization_invite.py @@ -1,5 +1,6 @@ from typing import Any, Optional, cast +import posthoganalytics from rest_framework import ( exceptions, mixins, @@ -9,11 +10,11 @@ status, viewsets, ) -from posthog.api.utils import action from ee.models.explicit_team_membership import ExplicitTeamMembership from posthog.api.routing import TeamAndOrgViewSetMixin from posthog.api.shared import UserBasicSerializer +from posthog.api.utils import action from posthog.email import is_email_available from posthog.event_usage import report_bulk_invited, report_team_member_invited from posthog.models import OrganizationInvite, OrganizationMembership @@ -119,6 +120,8 @@ def create(self, validated_data: dict[str, Any], *args: Any, **kwargs: Any) -> O ).count(), is_bulk=self.context.get("bulk_create", False), email_available=is_email_available(with_absolute_urls=True), + current_url=self.context.get("current_url"), + session_id=self.context.get("session_id"), ) return invite @@ -162,6 +165,19 @@ def create(self, request: request.Request, **kwargs) -> response.Response: @action(methods=["POST"], detail=False, required_scopes=["organization_member:write"]) def bulk(self, request: request.Request, **kwargs) -> response.Response: data = cast(Any, request.data) + user = cast(User, self.request.user) + current_url = request.headers.get("Referer") + session_id = request.headers.get("X-Posthog-Session-Id") + if user.distinct_id: + posthoganalytics.capture( + user.distinct_id, + "bulk invite attempted", + properties={ + "invitees_count": len(data), + "$current_url": current_url, + "$session_id": session_id, + }, + ) if not isinstance(data, list): raise exceptions.ValidationError("This endpoint needs an array of data for bulk invite creation.") if len(data) > 20: @@ -173,7 +189,12 @@ def bulk(self, request: request.Request, **kwargs) -> response.Response: serializer = OrganizationInviteSerializer( data=data, many=True, - context={**self.get_serializer_context(), "bulk_create": True}, + context={ + **self.get_serializer_context(), + "bulk_create": True, + "current_url": current_url, + "session_id": session_id, + }, ) serializer.is_valid(raise_exception=True) serializer.save() @@ -186,6 +207,8 @@ def bulk(self, request: request.Request, **kwargs) -> response.Response: current_invite_count=organization.active_invites.count(), current_member_count=organization.memberships.count(), email_available=is_email_available(), + current_url=current_url, + session_id=session_id, ) return response.Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/posthog/api/survey.py b/posthog/api/survey.py index f6f1dec80cb38..4e3bb5356ef1b 100644 --- a/posthog/api/survey.py +++ b/posthog/api/survey.py @@ -4,12 +4,12 @@ import nh3 from django.db.models import Min -from django.http import JsonResponse, HttpResponse +from django.http import HttpResponse, JsonResponse from django.utils.text import slugify from django.views.decorators.csrf import csrf_exempt +from loginas.utils import is_impersonated_session from nanoid import generate from rest_framework import request, serializers, status, viewsets -from posthog.api.utils import action from rest_framework.request import Request from rest_framework.response import Response @@ -21,19 +21,25 @@ ) from posthog.api.routing import TeamAndOrgViewSetMixin from posthog.api.shared import UserBasicSerializer -from posthog.api.utils import get_token +from posthog.api.utils import action, get_token from posthog.client import sync_execute -from posthog.models import Action from posthog.constants import AvailableFeature +from posthog.event_usage import report_user_action from posthog.exceptions import generate_exception_response -from posthog.models.activity_logging.activity_log import Change, changes_between, load_activity, log_activity, Detail +from posthog.models import Action +from posthog.models.activity_logging.activity_log import ( + Change, + Detail, + changes_between, + load_activity, + log_activity, +) from posthog.models.activity_logging.activity_page import activity_page_response from posthog.models.feature_flag.feature_flag import FeatureFlag from posthog.models.feedback.survey import Survey from posthog.models.team.team import Team from posthog.models.user import User from posthog.utils_cors import cors_response -from loginas.utils import is_impersonated_session SURVEY_TARGETING_FLAG_PREFIX = "survey-targeting-" ALLOWED_LINK_URL_SCHEMES = ["https", "mailto"] @@ -317,6 +323,7 @@ def create(self, validated_data): def update(self, instance: Survey, validated_data): before_update = Survey.objects.get(pk=instance.pk) + user = self.context["request"].user changes = [] if validated_data.get("remove_targeting_flag"): if instance.targeting_flag: @@ -370,6 +377,7 @@ def update(self, instance: Survey, validated_data): validated_data.pop("targeting_flag_filters") end_date = validated_data.get("end_date") + if instance.targeting_flag: # turn off feature flag if survey is completed if end_date is None: @@ -413,6 +421,39 @@ def update(self, instance: Survey, validated_data): detail=Detail(changes=changes, name=instance.name), ) + # Report survey events based on start_date and end_date changes + + properties = { + "name": instance.name, + "id": instance.id, + "survey_type": instance.type, + "question_types": [question.get("type") for question in instance.questions] if instance.questions else [], + "created_at": instance.created_at, + "start_date": instance.start_date, + "end_date": instance.end_date, + } + if before_update.start_date is None and instance.start_date is not None: + report_user_action( + user, + "survey launched", + properties, + team, + ) + elif before_update.end_date is None and instance.end_date is not None: + report_user_action( + user, + "survey stopped", + properties, + team, + ) + elif before_update.start_date is not None and before_update.end_date is not None and instance.end_date is None: + report_user_action( + user, + "survey resumed", + properties, + team, + ) + self._add_user_survey_interacted_filters(instance, end_date) self._associate_actions(instance, validated_data.get("conditions")) return instance diff --git a/posthog/api/test/__snapshots__/test_survey.ambr b/posthog/api/test/__snapshots__/test_survey.ambr index f99886b236db2..10f642ef9affd 100644 --- a/posthog/api/test/__snapshots__/test_survey.ambr +++ b/posthog/api/test/__snapshots__/test_survey.ambr @@ -11,18 +11,6 @@ GROUP BY survey_id ''' # --- -# name: TestResponsesCount.test_responses_count_only_after_first_survey_created - ''' - /* user_id:0 request:_snapshot_ */ - SELECT JSONExtractString(properties, '$survey_id') as survey_id, - count() - FROM events - WHERE event = 'survey sent' - AND team_id = 2 - AND timestamp >= '2024-04-25 14:40:09' - GROUP BY survey_id - ''' -# --- # name: TestResponsesCount.test_responses_count_only_after_first_survey_started ''' /* user_id:0 request:_snapshot_ */ diff --git a/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr b/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr index 853193cda1f92..fbfa40cef3d19 100644 --- a/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr +++ b/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr @@ -1581,6 +1581,89 @@ ''' # --- # name: TestDashboard.test_listing_dashboards_is_not_nplus1.16 + ''' + SELECT "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organization" + WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.17 + ''' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.18 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -1604,7 +1687,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.17 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.19 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -1625,7 +1708,39 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.18 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.2 + ''' + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 + ''' +# --- +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.20 ''' SELECT "posthog_dashboardtile"."dashboard_id" FROM "posthog_dashboardtile" @@ -1636,7 +1751,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.19 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.21 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -1663,39 +1778,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.2 - ''' - SELECT "posthog_organizationmembership"."id", - "posthog_organizationmembership"."organization_id", - "posthog_organizationmembership"."user_id", - "posthog_organizationmembership"."level", - "posthog_organizationmembership"."joined_at", - "posthog_organizationmembership"."updated_at", - "posthog_organization"."id", - "posthog_organization"."name", - "posthog_organization"."slug", - "posthog_organization"."logo_media_id", - "posthog_organization"."created_at", - "posthog_organization"."updated_at", - "posthog_organization"."plugins_access_level", - "posthog_organization"."for_internal_metrics", - "posthog_organization"."is_member_join_email_enabled", - "posthog_organization"."enforce_2fa", - "posthog_organization"."is_hipaa", - "posthog_organization"."customer_id", - "posthog_organization"."available_product_features", - "posthog_organization"."usage", - "posthog_organization"."never_drop_data", - "posthog_organization"."customer_trust_scores", - "posthog_organization"."setup_section_2_completed", - "posthog_organization"."personalization", - "posthog_organization"."domain_whitelist" - FROM "posthog_organizationmembership" - INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") - WHERE "posthog_organizationmembership"."user_id" = 2 - ''' -# --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.20 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.22 ''' SELECT "posthog_user"."id", "posthog_user"."password", @@ -1727,7 +1810,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.21 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.23 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -1784,7 +1867,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.22 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.24 ''' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -1816,7 +1899,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.23 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.25 ''' SELECT "posthog_organization"."id", "posthog_organization"."name", @@ -1842,7 +1925,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.24 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.26 ''' SELECT COUNT(*) AS "__count" FROM "posthog_dashboard" @@ -1851,7 +1934,7 @@ AND "posthog_team"."project_id" = 2) ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.25 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.27 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -1905,7 +1988,7 @@ LIMIT 300 ''' # --- -# name: TestDashboard.test_listing_dashboards_is_not_nplus1.26 +# name: TestDashboard.test_listing_dashboards_is_not_nplus1.28 ''' SELECT "posthog_sharingconfiguration"."id", "posthog_sharingconfiguration"."team_id", @@ -2523,6 +2606,38 @@ ''' # --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.100 + ''' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."strapi_id", + "posthog_user"."theme_mode", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."hedgehog_config", + "posthog_user"."events_column_config", + "posthog_user"."email_opt_in" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.101 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2572,13 +2687,6 @@ "posthog_team"."modifiers", "posthog_team"."correlation_config", "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical", "posthog_team"."external_data_workspace_id", "posthog_team"."external_data_workspace_last_synced_at" FROM "posthog_team" @@ -2586,7 +2694,39 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.101 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.102 + ''' + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.103 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -2606,14 +2746,11 @@ "posthog_dashboard"."is_shared" FROM "posthog_dashboard" WHERE (NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboard"."id" IN (1, - 2, - 3, - 4, - 5 /* ... */)) + AND "posthog_dashboard"."id" = 2) + LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.102 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.104 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2663,13 +2800,6 @@ "posthog_team"."modifiers", "posthog_team"."correlation_config", "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical", "posthog_team"."external_data_workspace_id", "posthog_team"."external_data_workspace_last_synced_at" FROM "posthog_team" @@ -2677,7 +2807,42 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.103 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.105 + ''' + SELECT "posthog_dashboarditem"."id", + "posthog_dashboarditem"."name", + "posthog_dashboarditem"."derived_name", + "posthog_dashboarditem"."description", + "posthog_dashboarditem"."team_id", + "posthog_dashboarditem"."filters", + "posthog_dashboarditem"."filters_hash", + "posthog_dashboarditem"."query", + "posthog_dashboarditem"."order", + "posthog_dashboarditem"."deleted", + "posthog_dashboarditem"."saved", + "posthog_dashboarditem"."created_at", + "posthog_dashboarditem"."refreshing", + "posthog_dashboarditem"."created_by_id", + "posthog_dashboarditem"."is_sample", + "posthog_dashboarditem"."short_id", + "posthog_dashboarditem"."favorited", + "posthog_dashboarditem"."refresh_attempt", + "posthog_dashboarditem"."last_modified_at", + "posthog_dashboarditem"."last_modified_by_id", + "posthog_dashboarditem"."dashboard_id", + "posthog_dashboarditem"."last_refresh", + "posthog_dashboarditem"."layouts", + "posthog_dashboarditem"."color", + "posthog_dashboarditem"."dive_dashboard_id", + "posthog_dashboarditem"."updated_at", + "posthog_dashboarditem"."deprecated_tags", + "posthog_dashboarditem"."tags" + FROM "posthog_dashboarditem" + WHERE "posthog_dashboarditem"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.106 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2741,7 +2906,34 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.104 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.107 + ''' + SELECT "posthog_dashboard"."id", + "posthog_dashboard"."name", + "posthog_dashboard"."description", + "posthog_dashboard"."team_id", + "posthog_dashboard"."pinned", + "posthog_dashboard"."created_at", + "posthog_dashboard"."created_by_id", + "posthog_dashboard"."deleted", + "posthog_dashboard"."last_accessed_at", + "posthog_dashboard"."filters", + "posthog_dashboard"."creation_mode", + "posthog_dashboard"."restriction_level", + "posthog_dashboard"."deprecated_tags", + "posthog_dashboard"."tags", + "posthog_dashboard"."share_token", + "posthog_dashboard"."is_shared" + FROM "posthog_dashboard" + WHERE (NOT ("posthog_dashboard"."deleted") + AND "posthog_dashboard"."id" IN (1, + 2, + 3, + 4, + 5 /* ... */)) + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.108 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2791,6 +2983,13 @@ "posthog_team"."modifiers", "posthog_team"."correlation_config", "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical", "posthog_team"."external_data_workspace_id", "posthog_team"."external_data_workspace_last_synced_at" FROM "posthog_team" @@ -2798,7 +2997,136 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.105 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.109 + ''' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.11 + ''' + SELECT "posthog_tag"."name" + FROM "posthog_taggeditem" + INNER JOIN "posthog_tag" ON ("posthog_taggeditem"."tag_id" = "posthog_tag"."id") + WHERE "posthog_taggeditem"."dashboard_id" = 2 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.110 + ''' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.111 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -2816,7 +3144,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.106 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.112 ''' SELECT "posthog_dashboarditem"."id", "posthog_dashboarditem"."name", @@ -2851,7 +3179,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.107 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.113 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -2874,7 +3202,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.108 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.114 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -2938,7 +3266,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.109 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.115 ''' SELECT "posthog_organization"."id", "posthog_organization"."name", @@ -2964,39 +3292,114 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.11 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.116 ''' - SELECT "posthog_tag"."name" - FROM "posthog_taggeditem" - INNER JOIN "posthog_tag" ON ("posthog_taggeditem"."tag_id" = "posthog_tag"."id") - WHERE "posthog_taggeditem"."dashboard_id" = 2 + SELECT "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organization" + WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid + LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.110 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.117 ''' - SELECT "posthog_dashboard"."id", - "posthog_dashboard"."name", - "posthog_dashboard"."description", - "posthog_dashboard"."team_id", - "posthog_dashboard"."pinned", - "posthog_dashboard"."created_at", - "posthog_dashboard"."created_by_id", - "posthog_dashboard"."deleted", - "posthog_dashboard"."last_accessed_at", - "posthog_dashboard"."filters", - "posthog_dashboard"."creation_mode", - "posthog_dashboard"."restriction_level", - "posthog_dashboard"."deprecated_tags", - "posthog_dashboard"."tags", - "posthog_dashboard"."share_token", - "posthog_dashboard"."is_shared" + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.118 + ''' + SELECT "posthog_dashboard"."id", + "posthog_dashboard"."name", + "posthog_dashboard"."description", + "posthog_dashboard"."team_id", + "posthog_dashboard"."pinned", + "posthog_dashboard"."created_at", + "posthog_dashboard"."created_by_id", + "posthog_dashboard"."deleted", + "posthog_dashboard"."last_accessed_at", + "posthog_dashboard"."filters", + "posthog_dashboard"."creation_mode", + "posthog_dashboard"."restriction_level", + "posthog_dashboard"."deprecated_tags", + "posthog_dashboard"."tags", + "posthog_dashboard"."share_token", + "posthog_dashboard"."is_shared" FROM "posthog_dashboard" INNER JOIN "posthog_dashboardtile" ON ("posthog_dashboard"."id" = "posthog_dashboardtile"."dashboard_id") WHERE (NOT ("posthog_dashboard"."deleted") AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.111 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.119 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -3017,7 +3420,39 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.112 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.12 + ''' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."strapi_id", + "posthog_user"."theme_mode", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."hedgehog_config", + "posthog_user"."events_column_config", + "posthog_user"."email_opt_in" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.120 ''' SELECT "posthog_dashboardtile"."dashboard_id" FROM "posthog_dashboardtile" @@ -3028,7 +3463,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.113 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.121 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -3055,7 +3490,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.114 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.122 ''' SELECT "posthog_tag"."name" FROM "posthog_taggeditem" @@ -3063,7 +3498,7 @@ WHERE "posthog_taggeditem"."insight_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.115 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.123 ''' SELECT "posthog_user"."id", "posthog_user"."password", @@ -3095,7 +3530,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.116 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.124 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -3152,7 +3587,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.117 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.125 ''' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -3184,7 +3619,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.118 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.126 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -3237,7 +3672,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.119 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.127 ''' SELECT "posthog_sharingconfiguration"."id", "posthog_sharingconfiguration"."team_id", @@ -3255,39 +3690,7 @@ 5 /* ... */) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.12 - ''' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."strapi_id", - "posthog_user"."theme_mode", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."hedgehog_config", - "posthog_user"."events_column_config", - "posthog_user"."email_opt_in" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 - LIMIT 21 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.120 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.128 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -3467,7 +3870,7 @@ ORDER BY "posthog_dashboarditem"."order" ASC ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.121 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.129 ''' SELECT "posthog_insightcachingstate"."id", "posthog_insightcachingstate"."team_id", @@ -3488,7 +3891,64 @@ 5 /* ... */) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.122 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.13 + ''' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.130 ''' SELECT ("posthog_dashboardtile"."insight_id") AS "_prefetch_related_val_insight_id", "posthog_dashboard"."id", @@ -3524,7 +3984,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.123 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.131 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -3549,7 +4009,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.124 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.132 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -3575,7 +4035,7 @@ 5 /* ... */) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.125 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.133 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -3756,7 +4216,7 @@ ORDER BY "posthog_dashboarditem"."order" ASC ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.126 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.134 ''' SELECT "posthog_insightcachingstate"."id", "posthog_insightcachingstate"."team_id", @@ -3777,7 +4237,7 @@ 5 /* ... */) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.127 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.135 ''' SELECT ("posthog_dashboardtile"."insight_id") AS "_prefetch_related_val_insight_id", "posthog_dashboard"."id", @@ -3813,7 +4273,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.128 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.136 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -3838,7 +4298,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.129 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.137 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -3864,64 +4324,7 @@ 5 /* ... */) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.13 - ''' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."project_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_web_vitals_opt_in", - "posthog_team"."autocapture_web_vitals_allowed_metrics", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."session_recording_sample_rate", - "posthog_team"."session_recording_minimum_duration_milliseconds", - "posthog_team"."session_recording_linked_flag", - "posthog_team"."session_recording_network_payload_capture_config", - "posthog_team"."session_replay_config", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."heatmaps_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."modifiers", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."external_data_workspace_id", - "posthog_team"."external_data_workspace_last_synced_at" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.130 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.138 ''' SELECT "posthog_taggeditem"."id", "posthog_taggeditem"."tag_id", @@ -3943,7 +4346,7 @@ 5 /* ... */) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.131 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.139 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -3970,9 +4373,15 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.132 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.14 ''' - SELECT "posthog_organization"."id", + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", "posthog_organization"."name", "posthog_organization"."slug", "posthog_organization"."logo_media_id", @@ -3991,28 +4400,14 @@ "posthog_organization"."setup_section_2_completed", "posthog_organization"."personalization", "posthog_organization"."domain_whitelist" - FROM "posthog_organization" - WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid - LIMIT 21 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.133 - ''' - SELECT "posthog_tag"."name" - FROM "posthog_taggeditem" - INNER JOIN "posthog_tag" ON ("posthog_taggeditem"."tag_id" = "posthog_tag"."id") - WHERE "posthog_taggeditem"."dashboard_id" = 2 + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.14 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.140 ''' - SELECT "posthog_organizationmembership"."id", - "posthog_organizationmembership"."organization_id", - "posthog_organizationmembership"."user_id", - "posthog_organizationmembership"."level", - "posthog_organizationmembership"."joined_at", - "posthog_organizationmembership"."updated_at", - "posthog_organization"."id", + SELECT "posthog_organization"."id", "posthog_organization"."name", "posthog_organization"."slug", "posthog_organization"."logo_media_id", @@ -4031,9 +4426,17 @@ "posthog_organization"."setup_section_2_completed", "posthog_organization"."personalization", "posthog_organization"."domain_whitelist" - FROM "posthog_organizationmembership" - INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") - WHERE "posthog_organizationmembership"."user_id" = 2 + FROM "posthog_organization" + WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.141 + ''' + SELECT "posthog_tag"."name" + FROM "posthog_taggeditem" + INNER JOIN "posthog_tag" ON ("posthog_taggeditem"."tag_id" = "posthog_tag"."id") + WHERE "posthog_taggeditem"."dashboard_id" = 2 ''' # --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.15 @@ -5401,6 +5804,89 @@ ''' # --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.47 + ''' + SELECT "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organization" + WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.48 + ''' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.49 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -5424,7 +5910,19 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.48 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.5 + ''' + SELECT COUNT(*) AS "__count" + FROM "posthog_dashboardtile" + INNER JOIN "posthog_dashboard" ON ("posthog_dashboardtile"."dashboard_id" = "posthog_dashboard"."id") + WHERE (NOT ("posthog_dashboardtile"."deleted" + AND "posthog_dashboardtile"."deleted" IS NOT NULL) + AND NOT ("posthog_dashboard"."deleted") + AND "posthog_dashboardtile"."dashboard_id" = 2 + AND NOT ("posthog_dashboardtile"."insight_id" IS NULL)) + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.50 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -5445,7 +5943,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.49 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.51 ''' SELECT "posthog_dashboardtile"."dashboard_id" FROM "posthog_dashboardtile" @@ -5456,19 +5954,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.5 - ''' - SELECT COUNT(*) AS "__count" - FROM "posthog_dashboardtile" - INNER JOIN "posthog_dashboard" ON ("posthog_dashboardtile"."dashboard_id" = "posthog_dashboard"."id") - WHERE (NOT ("posthog_dashboardtile"."deleted" - AND "posthog_dashboardtile"."deleted" IS NOT NULL) - AND NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboardtile"."dashboard_id" = 2 - AND NOT ("posthog_dashboardtile"."insight_id" IS NULL)) - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.50 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.52 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -5495,7 +5981,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.51 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.53 ''' SELECT "posthog_tag"."name" FROM "posthog_taggeditem" @@ -5503,7 +5989,7 @@ WHERE "posthog_taggeditem"."insight_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.52 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.54 ''' SELECT "posthog_user"."id", "posthog_user"."password", @@ -5535,7 +6021,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.53 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.55 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -5592,7 +6078,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.54 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.56 ''' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -5624,7 +6110,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.55 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.57 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -5648,7 +6134,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.56 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.58 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -5705,7 +6191,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.57 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.59 ''' SELECT "posthog_dashboarditem"."id", "posthog_dashboarditem"."name", @@ -5740,7 +6226,21 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.58 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.6 + ''' + SELECT "posthog_sharingconfiguration"."id", + "posthog_sharingconfiguration"."team_id", + "posthog_sharingconfiguration"."dashboard_id", + "posthog_sharingconfiguration"."insight_id", + "posthog_sharingconfiguration"."recording_id", + "posthog_sharingconfiguration"."created_at", + "posthog_sharingconfiguration"."enabled", + "posthog_sharingconfiguration"."access_token" + FROM "posthog_sharingconfiguration" + WHERE "posthog_sharingconfiguration"."dashboard_id" = 2 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.60 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -5804,7 +6304,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.59 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.61 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -5831,21 +6331,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.6 - ''' - SELECT "posthog_sharingconfiguration"."id", - "posthog_sharingconfiguration"."team_id", - "posthog_sharingconfiguration"."dashboard_id", - "posthog_sharingconfiguration"."insight_id", - "posthog_sharingconfiguration"."recording_id", - "posthog_sharingconfiguration"."created_at", - "posthog_sharingconfiguration"."enabled", - "posthog_sharingconfiguration"."access_token" - FROM "posthog_sharingconfiguration" - WHERE "posthog_sharingconfiguration"."dashboard_id" = 2 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.60 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.62 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -5909,7 +6395,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.61 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.63 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -5973,7 +6459,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.62 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.64 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6030,7 +6516,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.63 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.65 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -6048,7 +6534,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.64 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.66 ''' SELECT "posthog_dashboarditem"."id", "posthog_dashboarditem"."name", @@ -6083,7 +6569,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.65 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.67 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -6106,7 +6592,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.66 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.68 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6170,7 +6656,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.67 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.69 ''' SELECT "posthog_organization"."id", "posthog_organization"."name", @@ -6196,10 +6682,100 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.68 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.7 ''' - SELECT "posthog_dashboard"."id", - "posthog_dashboard"."name", + SELECT COUNT(*) AS "__count" + FROM "posthog_taggeditem" + WHERE "posthog_taggeditem"."dashboard_id" = 2 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.70 + ''' + SELECT "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organization" + WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.71 + ''' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."project_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."has_completed_onboarding_for", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_web_vitals_opt_in", + "posthog_team"."autocapture_web_vitals_allowed_metrics", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."session_recording_sample_rate", + "posthog_team"."session_recording_minimum_duration_milliseconds", + "posthog_team"."session_recording_linked_flag", + "posthog_team"."session_recording_network_payload_capture_config", + "posthog_team"."session_replay_config", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."surveys_opt_in", + "posthog_team"."heatmaps_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."week_start_day", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."modifiers", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."external_data_workspace_id", + "posthog_team"."external_data_workspace_last_synced_at" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.72 + ''' + SELECT "posthog_dashboard"."id", + "posthog_dashboard"."name", "posthog_dashboard"."description", "posthog_dashboard"."team_id", "posthog_dashboard"."pinned", @@ -6220,7 +6796,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.69 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.73 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -6241,14 +6817,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.7 - ''' - SELECT COUNT(*) AS "__count" - FROM "posthog_taggeditem" - WHERE "posthog_taggeditem"."dashboard_id" = 2 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.70 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.74 ''' SELECT "posthog_dashboardtile"."dashboard_id" FROM "posthog_dashboardtile" @@ -6259,7 +6828,7 @@ AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.71 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.75 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -6286,7 +6855,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.72 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.76 ''' SELECT "posthog_tag"."name" FROM "posthog_taggeditem" @@ -6294,7 +6863,7 @@ WHERE "posthog_taggeditem"."insight_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.73 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.77 ''' SELECT "posthog_user"."id", "posthog_user"."password", @@ -6326,7 +6895,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.74 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.78 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6383,7 +6952,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.75 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.79 ''' SELECT "posthog_organizationmembership"."id", "posthog_organizationmembership"."organization_id", @@ -6415,31 +6984,7 @@ WHERE "posthog_organizationmembership"."user_id" = 2 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.76 - ''' - SELECT "posthog_dashboard"."id", - "posthog_dashboard"."name", - "posthog_dashboard"."description", - "posthog_dashboard"."team_id", - "posthog_dashboard"."pinned", - "posthog_dashboard"."created_at", - "posthog_dashboard"."created_by_id", - "posthog_dashboard"."deleted", - "posthog_dashboard"."last_accessed_at", - "posthog_dashboard"."filters", - "posthog_dashboard"."creation_mode", - "posthog_dashboard"."restriction_level", - "posthog_dashboard"."deprecated_tags", - "posthog_dashboard"."tags", - "posthog_dashboard"."share_token", - "posthog_dashboard"."is_shared" - FROM "posthog_dashboard" - WHERE (NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboard"."id" = 2) - LIMIT 21 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.77 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.8 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6489,6 +7034,13 @@ "posthog_team"."modifiers", "posthog_team"."correlation_config", "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical", "posthog_team"."external_data_workspace_id", "posthog_team"."external_data_workspace_last_synced_at" FROM "posthog_team" @@ -6496,42 +7048,31 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.78 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.80 ''' - SELECT "posthog_dashboarditem"."id", - "posthog_dashboarditem"."name", - "posthog_dashboarditem"."derived_name", - "posthog_dashboarditem"."description", - "posthog_dashboarditem"."team_id", - "posthog_dashboarditem"."filters", - "posthog_dashboarditem"."filters_hash", - "posthog_dashboarditem"."query", - "posthog_dashboarditem"."order", - "posthog_dashboarditem"."deleted", - "posthog_dashboarditem"."saved", - "posthog_dashboarditem"."created_at", - "posthog_dashboarditem"."refreshing", - "posthog_dashboarditem"."created_by_id", - "posthog_dashboarditem"."is_sample", - "posthog_dashboarditem"."short_id", - "posthog_dashboarditem"."favorited", - "posthog_dashboarditem"."refresh_attempt", - "posthog_dashboarditem"."last_modified_at", - "posthog_dashboarditem"."last_modified_by_id", - "posthog_dashboarditem"."dashboard_id", - "posthog_dashboarditem"."last_refresh", - "posthog_dashboarditem"."layouts", - "posthog_dashboarditem"."color", - "posthog_dashboarditem"."dive_dashboard_id", - "posthog_dashboarditem"."updated_at", - "posthog_dashboarditem"."deprecated_tags", - "posthog_dashboarditem"."tags" - FROM "posthog_dashboarditem" - WHERE "posthog_dashboarditem"."id" = 2 + SELECT "posthog_dashboard"."id", + "posthog_dashboard"."name", + "posthog_dashboard"."description", + "posthog_dashboard"."team_id", + "posthog_dashboard"."pinned", + "posthog_dashboard"."created_at", + "posthog_dashboard"."created_by_id", + "posthog_dashboard"."deleted", + "posthog_dashboard"."last_accessed_at", + "posthog_dashboard"."filters", + "posthog_dashboard"."creation_mode", + "posthog_dashboard"."restriction_level", + "posthog_dashboard"."deprecated_tags", + "posthog_dashboard"."tags", + "posthog_dashboard"."share_token", + "posthog_dashboard"."is_shared" + FROM "posthog_dashboard" + WHERE (NOT ("posthog_dashboard"."deleted") + AND "posthog_dashboard"."id" = 2) LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.79 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.81 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6581,13 +7122,6 @@ "posthog_team"."modifiers", "posthog_team"."correlation_config", "posthog_team"."session_recording_retention_period_days", - "posthog_team"."plugins_opt_in", - "posthog_team"."opt_out_capture", - "posthog_team"."event_names", - "posthog_team"."event_names_with_usage", - "posthog_team"."event_properties", - "posthog_team"."event_properties_with_usage", - "posthog_team"."event_properties_numerical", "posthog_team"."external_data_workspace_id", "posthog_team"."external_data_workspace_last_synced_at" FROM "posthog_team" @@ -6595,7 +7129,42 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.8 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.82 + ''' + SELECT "posthog_dashboarditem"."id", + "posthog_dashboarditem"."name", + "posthog_dashboarditem"."derived_name", + "posthog_dashboarditem"."description", + "posthog_dashboarditem"."team_id", + "posthog_dashboarditem"."filters", + "posthog_dashboarditem"."filters_hash", + "posthog_dashboarditem"."query", + "posthog_dashboarditem"."order", + "posthog_dashboarditem"."deleted", + "posthog_dashboarditem"."saved", + "posthog_dashboarditem"."created_at", + "posthog_dashboarditem"."refreshing", + "posthog_dashboarditem"."created_by_id", + "posthog_dashboarditem"."is_sample", + "posthog_dashboarditem"."short_id", + "posthog_dashboarditem"."favorited", + "posthog_dashboarditem"."refresh_attempt", + "posthog_dashboarditem"."last_modified_at", + "posthog_dashboarditem"."last_modified_by_id", + "posthog_dashboarditem"."dashboard_id", + "posthog_dashboarditem"."last_refresh", + "posthog_dashboarditem"."layouts", + "posthog_dashboarditem"."color", + "posthog_dashboarditem"."dive_dashboard_id", + "posthog_dashboarditem"."updated_at", + "posthog_dashboarditem"."deprecated_tags", + "posthog_dashboarditem"."tags" + FROM "posthog_dashboarditem" + WHERE "posthog_dashboarditem"."id" = 2 + LIMIT 21 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.83 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6659,7 +7228,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.80 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.84 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -6686,7 +7255,7 @@ 5 /* ... */)) ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.81 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.85 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6750,7 +7319,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.82 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.86 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6814,7 +7383,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.83 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.87 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -6871,7 +7440,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.84 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.88 ''' SELECT "posthog_dashboardtile"."id", "posthog_dashboardtile"."dashboard_id", @@ -6889,7 +7458,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.85 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.89 ''' SELECT "posthog_dashboarditem"."id", "posthog_dashboarditem"."name", @@ -6924,7 +7493,21 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.86 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.9 + ''' + SELECT "posthog_sharingconfiguration"."id", + "posthog_sharingconfiguration"."team_id", + "posthog_sharingconfiguration"."dashboard_id", + "posthog_sharingconfiguration"."insight_id", + "posthog_sharingconfiguration"."recording_id", + "posthog_sharingconfiguration"."created_at", + "posthog_sharingconfiguration"."enabled", + "posthog_sharingconfiguration"."access_token" + FROM "posthog_sharingconfiguration" + WHERE "posthog_sharingconfiguration"."dashboard_id" = 2 + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.90 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -6947,7 +7530,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.87 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.91 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -7011,7 +7594,7 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.88 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.92 ''' SELECT "posthog_organization"."id", "posthog_organization"."name", @@ -7037,144 +7620,33 @@ LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.89 - ''' - SELECT "posthog_dashboard"."id", - "posthog_dashboard"."name", - "posthog_dashboard"."description", - "posthog_dashboard"."team_id", - "posthog_dashboard"."pinned", - "posthog_dashboard"."created_at", - "posthog_dashboard"."created_by_id", - "posthog_dashboard"."deleted", - "posthog_dashboard"."last_accessed_at", - "posthog_dashboard"."filters", - "posthog_dashboard"."creation_mode", - "posthog_dashboard"."restriction_level", - "posthog_dashboard"."deprecated_tags", - "posthog_dashboard"."tags", - "posthog_dashboard"."share_token", - "posthog_dashboard"."is_shared" - FROM "posthog_dashboard" - INNER JOIN "posthog_dashboardtile" ON ("posthog_dashboard"."id" = "posthog_dashboardtile"."dashboard_id") - WHERE (NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboardtile"."insight_id" = 2) - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.9 - ''' - SELECT "posthog_sharingconfiguration"."id", - "posthog_sharingconfiguration"."team_id", - "posthog_sharingconfiguration"."dashboard_id", - "posthog_sharingconfiguration"."insight_id", - "posthog_sharingconfiguration"."recording_id", - "posthog_sharingconfiguration"."created_at", - "posthog_sharingconfiguration"."enabled", - "posthog_sharingconfiguration"."access_token" - FROM "posthog_sharingconfiguration" - WHERE "posthog_sharingconfiguration"."dashboard_id" = 2 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.90 - ''' - SELECT "posthog_dashboardtile"."id", - "posthog_dashboardtile"."dashboard_id", - "posthog_dashboardtile"."insight_id", - "posthog_dashboardtile"."text_id", - "posthog_dashboardtile"."layouts", - "posthog_dashboardtile"."color", - "posthog_dashboardtile"."filters_hash", - "posthog_dashboardtile"."last_refresh", - "posthog_dashboardtile"."refreshing", - "posthog_dashboardtile"."refresh_attempt", - "posthog_dashboardtile"."deleted" - FROM "posthog_dashboardtile" - INNER JOIN "posthog_dashboard" ON ("posthog_dashboardtile"."dashboard_id" = "posthog_dashboard"."id") - WHERE (NOT ("posthog_dashboardtile"."deleted" - AND "posthog_dashboardtile"."deleted" IS NOT NULL) - AND NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboardtile"."insight_id" = 2) - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.91 - ''' - SELECT "posthog_dashboardtile"."dashboard_id" - FROM "posthog_dashboardtile" - INNER JOIN "posthog_dashboard" ON ("posthog_dashboardtile"."dashboard_id" = "posthog_dashboard"."id") - WHERE (NOT ("posthog_dashboardtile"."deleted" - AND "posthog_dashboardtile"."deleted" IS NOT NULL) - AND NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboardtile"."insight_id" = 2) - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.92 - ''' - SELECT "posthog_dashboard"."id", - "posthog_dashboard"."name", - "posthog_dashboard"."description", - "posthog_dashboard"."team_id", - "posthog_dashboard"."pinned", - "posthog_dashboard"."created_at", - "posthog_dashboard"."created_by_id", - "posthog_dashboard"."deleted", - "posthog_dashboard"."last_accessed_at", - "posthog_dashboard"."filters", - "posthog_dashboard"."creation_mode", - "posthog_dashboard"."restriction_level", - "posthog_dashboard"."deprecated_tags", - "posthog_dashboard"."tags", - "posthog_dashboard"."share_token", - "posthog_dashboard"."is_shared" - FROM "posthog_dashboard" - WHERE (NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboard"."id" IN (1, - 2, - 3, - 4, - 5 /* ... */)) - ''' -# --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.93 ''' - SELECT "posthog_tag"."name" - FROM "posthog_taggeditem" - INNER JOIN "posthog_tag" ON ("posthog_taggeditem"."tag_id" = "posthog_tag"."id") - WHERE "posthog_taggeditem"."insight_id" = 2 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.94 - ''' - SELECT "posthog_user"."id", - "posthog_user"."password", - "posthog_user"."last_login", - "posthog_user"."first_name", - "posthog_user"."last_name", - "posthog_user"."is_staff", - "posthog_user"."is_active", - "posthog_user"."date_joined", - "posthog_user"."uuid", - "posthog_user"."current_organization_id", - "posthog_user"."current_team_id", - "posthog_user"."email", - "posthog_user"."pending_email", - "posthog_user"."temporary_token", - "posthog_user"."distinct_id", - "posthog_user"."is_email_verified", - "posthog_user"."has_seen_product_intro_for", - "posthog_user"."strapi_id", - "posthog_user"."theme_mode", - "posthog_user"."partial_notification_settings", - "posthog_user"."anonymize_data", - "posthog_user"."toolbar_mode", - "posthog_user"."hedgehog_config", - "posthog_user"."events_column_config", - "posthog_user"."email_opt_in" - FROM "posthog_user" - WHERE "posthog_user"."id" = 2 + SELECT "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."logo_media_id", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."is_hipaa", + "posthog_organization"."customer_id", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."never_drop_data", + "posthog_organization"."customer_trust_scores", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organization" + WHERE "posthog_organization"."id" = '00000000-0000-0000-0000-000000000000'::uuid LIMIT 21 ''' # --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.95 +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.94 ''' SELECT "posthog_team"."id", "posthog_team"."uuid", @@ -7231,39 +7703,63 @@ LIMIT 21 ''' # --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.95 + ''' + SELECT "posthog_dashboard"."id", + "posthog_dashboard"."name", + "posthog_dashboard"."description", + "posthog_dashboard"."team_id", + "posthog_dashboard"."pinned", + "posthog_dashboard"."created_at", + "posthog_dashboard"."created_by_id", + "posthog_dashboard"."deleted", + "posthog_dashboard"."last_accessed_at", + "posthog_dashboard"."filters", + "posthog_dashboard"."creation_mode", + "posthog_dashboard"."restriction_level", + "posthog_dashboard"."deprecated_tags", + "posthog_dashboard"."tags", + "posthog_dashboard"."share_token", + "posthog_dashboard"."is_shared" + FROM "posthog_dashboard" + INNER JOIN "posthog_dashboardtile" ON ("posthog_dashboard"."id" = "posthog_dashboardtile"."dashboard_id") + WHERE (NOT ("posthog_dashboard"."deleted") + AND "posthog_dashboardtile"."insight_id" = 2) + ''' +# --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.96 ''' - SELECT "posthog_organizationmembership"."id", - "posthog_organizationmembership"."organization_id", - "posthog_organizationmembership"."user_id", - "posthog_organizationmembership"."level", - "posthog_organizationmembership"."joined_at", - "posthog_organizationmembership"."updated_at", - "posthog_organization"."id", - "posthog_organization"."name", - "posthog_organization"."slug", - "posthog_organization"."logo_media_id", - "posthog_organization"."created_at", - "posthog_organization"."updated_at", - "posthog_organization"."plugins_access_level", - "posthog_organization"."for_internal_metrics", - "posthog_organization"."is_member_join_email_enabled", - "posthog_organization"."enforce_2fa", - "posthog_organization"."is_hipaa", - "posthog_organization"."customer_id", - "posthog_organization"."available_product_features", - "posthog_organization"."usage", - "posthog_organization"."never_drop_data", - "posthog_organization"."customer_trust_scores", - "posthog_organization"."setup_section_2_completed", - "posthog_organization"."personalization", - "posthog_organization"."domain_whitelist" - FROM "posthog_organizationmembership" - INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") - WHERE "posthog_organizationmembership"."user_id" = 2 + SELECT "posthog_dashboardtile"."id", + "posthog_dashboardtile"."dashboard_id", + "posthog_dashboardtile"."insight_id", + "posthog_dashboardtile"."text_id", + "posthog_dashboardtile"."layouts", + "posthog_dashboardtile"."color", + "posthog_dashboardtile"."filters_hash", + "posthog_dashboardtile"."last_refresh", + "posthog_dashboardtile"."refreshing", + "posthog_dashboardtile"."refresh_attempt", + "posthog_dashboardtile"."deleted" + FROM "posthog_dashboardtile" + INNER JOIN "posthog_dashboard" ON ("posthog_dashboardtile"."dashboard_id" = "posthog_dashboard"."id") + WHERE (NOT ("posthog_dashboardtile"."deleted" + AND "posthog_dashboardtile"."deleted" IS NOT NULL) + AND NOT ("posthog_dashboard"."deleted") + AND "posthog_dashboardtile"."insight_id" = 2) ''' # --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.97 + ''' + SELECT "posthog_dashboardtile"."dashboard_id" + FROM "posthog_dashboardtile" + INNER JOIN "posthog_dashboard" ON ("posthog_dashboardtile"."dashboard_id" = "posthog_dashboard"."id") + WHERE (NOT ("posthog_dashboardtile"."deleted" + AND "posthog_dashboardtile"."deleted" IS NOT NULL) + AND NOT ("posthog_dashboard"."deleted") + AND "posthog_dashboardtile"."insight_id" = 2) + ''' +# --- +# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.98 ''' SELECT "posthog_dashboard"."id", "posthog_dashboard"."name", @@ -7283,100 +7779,19 @@ "posthog_dashboard"."is_shared" FROM "posthog_dashboard" WHERE (NOT ("posthog_dashboard"."deleted") - AND "posthog_dashboard"."id" = 2) - LIMIT 21 - ''' -# --- -# name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.98 - ''' - SELECT "posthog_team"."id", - "posthog_team"."uuid", - "posthog_team"."organization_id", - "posthog_team"."project_id", - "posthog_team"."api_token", - "posthog_team"."app_urls", - "posthog_team"."name", - "posthog_team"."slack_incoming_webhook", - "posthog_team"."created_at", - "posthog_team"."updated_at", - "posthog_team"."anonymize_ips", - "posthog_team"."completed_snippet_onboarding", - "posthog_team"."has_completed_onboarding_for", - "posthog_team"."ingested_event", - "posthog_team"."autocapture_opt_out", - "posthog_team"."autocapture_web_vitals_opt_in", - "posthog_team"."autocapture_web_vitals_allowed_metrics", - "posthog_team"."autocapture_exceptions_opt_in", - "posthog_team"."autocapture_exceptions_errors_to_ignore", - "posthog_team"."session_recording_opt_in", - "posthog_team"."session_recording_sample_rate", - "posthog_team"."session_recording_minimum_duration_milliseconds", - "posthog_team"."session_recording_linked_flag", - "posthog_team"."session_recording_network_payload_capture_config", - "posthog_team"."session_replay_config", - "posthog_team"."capture_console_log_opt_in", - "posthog_team"."capture_performance_opt_in", - "posthog_team"."surveys_opt_in", - "posthog_team"."heatmaps_opt_in", - "posthog_team"."session_recording_version", - "posthog_team"."signup_token", - "posthog_team"."is_demo", - "posthog_team"."access_control", - "posthog_team"."week_start_day", - "posthog_team"."inject_web_apps", - "posthog_team"."test_account_filters", - "posthog_team"."test_account_filters_default_checked", - "posthog_team"."path_cleaning_filters", - "posthog_team"."timezone", - "posthog_team"."data_attributes", - "posthog_team"."person_display_name_properties", - "posthog_team"."live_events_columns", - "posthog_team"."recording_domains", - "posthog_team"."primary_dashboard_id", - "posthog_team"."extra_settings", - "posthog_team"."modifiers", - "posthog_team"."correlation_config", - "posthog_team"."session_recording_retention_period_days", - "posthog_team"."external_data_workspace_id", - "posthog_team"."external_data_workspace_last_synced_at" - FROM "posthog_team" - WHERE "posthog_team"."id" = 2 - LIMIT 21 + AND "posthog_dashboard"."id" IN (1, + 2, + 3, + 4, + 5 /* ... */)) ''' # --- # name: TestDashboard.test_loading_individual_dashboard_does_not_prefetch_all_possible_tiles.99 ''' - SELECT "posthog_dashboarditem"."id", - "posthog_dashboarditem"."name", - "posthog_dashboarditem"."derived_name", - "posthog_dashboarditem"."description", - "posthog_dashboarditem"."team_id", - "posthog_dashboarditem"."filters", - "posthog_dashboarditem"."filters_hash", - "posthog_dashboarditem"."query", - "posthog_dashboarditem"."order", - "posthog_dashboarditem"."deleted", - "posthog_dashboarditem"."saved", - "posthog_dashboarditem"."created_at", - "posthog_dashboarditem"."refreshing", - "posthog_dashboarditem"."created_by_id", - "posthog_dashboarditem"."is_sample", - "posthog_dashboarditem"."short_id", - "posthog_dashboarditem"."favorited", - "posthog_dashboarditem"."refresh_attempt", - "posthog_dashboarditem"."last_modified_at", - "posthog_dashboarditem"."last_modified_by_id", - "posthog_dashboarditem"."dashboard_id", - "posthog_dashboarditem"."last_refresh", - "posthog_dashboarditem"."layouts", - "posthog_dashboarditem"."color", - "posthog_dashboarditem"."dive_dashboard_id", - "posthog_dashboarditem"."updated_at", - "posthog_dashboarditem"."deprecated_tags", - "posthog_dashboarditem"."tags" - FROM "posthog_dashboarditem" - WHERE "posthog_dashboarditem"."id" = 2 - LIMIT 21 + SELECT "posthog_tag"."name" + FROM "posthog_taggeditem" + INNER JOIN "posthog_tag" ON ("posthog_taggeditem"."tag_id" = "posthog_tag"."id") + WHERE "posthog_taggeditem"."insight_id" = 2 ''' # --- # name: TestDashboard.test_retrieve_dashboard diff --git a/posthog/api/test/dashboards/test_dashboard.py b/posthog/api/test/dashboards/test_dashboard.py index b5a68371f3059..d3e7e43d7f200 100644 --- a/posthog/api/test/dashboards/test_dashboard.py +++ b/posthog/api/test/dashboards/test_dashboard.py @@ -712,6 +712,8 @@ def test_dashboard_from_template(self, mock_capture): self.user, "dashboard created", { + "$current_url": None, + "$session_id": mock.ANY, "created_at": mock.ANY, "dashboard_id": None, "duplicated": False, @@ -1153,6 +1155,7 @@ def test_create_from_template_json(self, mock_capture) -> None: response = self.client.post( f"/api/projects/{self.team.id}/dashboards/create_from_template_json", {"template": valid_template, "creation_context": "onboarding"}, + headers={"Referer": "https://posthog.com/my-referer", "X-Posthog-Session-Id": "my-session-id"}, ) self.assertEqual(response.status_code, 200, response.content) @@ -1172,6 +1175,8 @@ def test_create_from_template_json(self, mock_capture) -> None: self.user, "dashboard created", { + "$current_url": "https://posthog.com/my-referer", + "$session_id": "my-session-id", "created_at": mock.ANY, "creation_context": "onboarding", "dashboard_id": dashboard["id"], diff --git a/posthog/api/test/test_insight.py b/posthog/api/test/test_insight.py index 3ec4f2d3046c6..6834ae2d6c40f 100644 --- a/posthog/api/test/test_insight.py +++ b/posthog/api/test/test_insight.py @@ -3,7 +3,7 @@ from typing import Any, Optional from unittest import mock from unittest.case import skip -from unittest.mock import patch +from unittest.mock import ANY, patch from zoneinfo import ZoneInfo from django.test import override_settings @@ -91,7 +91,8 @@ def test_get_insight_items(self) -> None: self.assertEqual(len(response["results"]), 1) - def test_created_updated_and_last_modified(self) -> None: + @patch("posthoganalytics.capture") + def test_created_updated_and_last_modified(self, mock_capture: mock.Mock) -> None: alt_user = User.objects.create_and_join(self.organization, "team2@posthog.com", None) self_user_basic_serialized = { "id": self.user.id, @@ -117,7 +118,11 @@ def test_created_updated_and_last_modified(self) -> None: # Newly created insight should have created_at being the current time, and same last_modified_at # Fields created_by and last_modified_by should be set to the current user with freeze_time("2021-08-23T12:00:00Z"): - response_1 = self.client.post(f"/api/projects/{self.team.id}/insights/") + response_1 = self.client.post( + f"/api/projects/{self.team.id}/insights/", + {"name": "test"}, + headers={"Referer": "https://posthog.com/my-referer", "X-Posthog-Session-Id": "my-session-id"}, + ) self.assertEqual(response_1.status_code, status.HTTP_201_CREATED) self.assertDictContainsSubset( { @@ -129,6 +134,17 @@ def test_created_updated_and_last_modified(self) -> None: }, response_1.json(), ) + mock_capture.assert_called_once_with( + self.user.distinct_id, + "insight created", + { + "insight_id": response_1.json()["short_id"], + "$current_url": "https://posthog.com/my-referer", + "$session_id": "my-session-id", + }, + groups=ANY, + ) + mock_capture.reset_mock() insight_id = response_1.json()["id"] @@ -138,6 +154,7 @@ def test_created_updated_and_last_modified(self) -> None: response_2 = self.client.patch( f"/api/projects/{self.team.id}/insights/{insight_id}", {"favorited": True}, + headers={"Referer": "https://posthog.com/my-referer", "X-Posthog-Session-Id": "my-session-id"}, ) self.assertEqual(response_2.status_code, status.HTTP_200_OK) self.assertDictContainsSubset( @@ -150,6 +167,18 @@ def test_created_updated_and_last_modified(self) -> None: }, response_2.json(), ) + insight_short_id = response_2.json()["short_id"] + mock_capture.assert_called_once_with( + self.user.distinct_id, + "insight updated", + { + "insight_id": insight_short_id, + "$current_url": "https://posthog.com/my-referer", + "$session_id": "my-session-id", + }, + groups=ANY, + ) + mock_capture.reset_mock() # Updating fields that DO change the substance of the insight should affect updated_at # AND last_modified_at plus last_modified_by diff --git a/posthog/api/test/test_organization_invites.py b/posthog/api/test/test_organization_invites.py index 351d2b21aabc9..1e6499a37d3ac 100644 --- a/posthog/api/test/test_organization_invites.py +++ b/posthog/api/test/test_organization_invites.py @@ -68,7 +68,10 @@ def test_add_organization_invite_with_email(self, mock_capture): email = "x@x.com" with self.settings(EMAIL_ENABLED=True, SITE_URL="http://test.posthog.com"): - response = self.client.post("/api/organizations/@current/invites/", {"target_email": email}) + response = self.client.post( + "/api/organizations/@current/invites/", + {"target_email": email}, + ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertTrue(OrganizationInvite.objects.exists()) @@ -118,8 +121,8 @@ def test_add_organization_invite_with_email(self, mock_capture): # Assert capture call for inviting party mock_capture.assert_any_call( self.user.distinct_id, - "team invite executed", - properties=capture_props, + "team member invited", + properties={**capture_props, "$current_url": None, "$session_id": None}, groups={ "instance": ANY, "organization": str(self.team.organization_id), @@ -331,7 +334,12 @@ def test_allow_bulk_creating_invites(self, mock_capture): payload = self.helper_generate_bulk_invite_payload(7) with self.settings(EMAIL_ENABLED=True, SITE_URL="http://test.posthog.com"): - response = self.client.post("/api/organizations/@current/invites/bulk/", payload, format="json") + response = self.client.post( + "/api/organizations/@current/invites/bulk/", + payload, + format="json", + headers={"X-Posthog-Session-Id": "123", "Referer": "http://test.posthog.com/my-url"}, + ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) response_data = response.json() @@ -360,6 +368,8 @@ def test_allow_bulk_creating_invites(self, mock_capture): "current_invite_count": 7, "current_member_count": 1, "email_available": True, + "$session_id": "123", + "$current_url": "http://test.posthog.com/my-url", }, groups={ "instance": ANY, diff --git a/posthog/api/test/test_survey.py b/posthog/api/test/test_survey.py index 855e5171d3ce7..e77e41d2e489b 100644 --- a/posthog/api/test/test_survey.py +++ b/posthog/api/test/test_survey.py @@ -1,7 +1,7 @@ import re -from datetime import datetime, timedelta +from datetime import datetime, timedelta, UTC from typing import Any -from unittest.mock import ANY +from unittest.mock import ANY, patch import pytest from django.core.cache import cache @@ -1341,6 +1341,83 @@ def test_update_survey_records_activity(self): ], ) + @patch("posthog.api.survey.report_user_action") + @freeze_time("2023-05-01 12:00:00") + def test_update_survey_dates_calls_report_user_action(self, mock_report_user_action): + survey = Survey.objects.create( + team=self.team, + name="Date Test Survey", + type="popover", + questions=[{"type": "open", "question": "Test question?"}], + ) + + start_date = datetime(2023, 5, 2, tzinfo=UTC) + end_date = datetime(2023, 5, 10, tzinfo=UTC) + + # set the start date / aka launch survey + response = self.client.patch( + f"/api/projects/{self.team.id}/surveys/{survey.id}/", + data={"start_date": start_date}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + expected_properties = { + "name": "Date Test Survey", + "id": survey.id, + "survey_type": "popover", + "question_types": ["open"], + "created_at": survey.created_at, + } + + mock_report_user_action.assert_called_once_with( + self.user, + "survey launched", + { + **expected_properties, + "start_date": start_date, + "end_date": None, + }, + self.team, + ) + mock_report_user_action.reset_mock() + + # set the end date / aka stop survey + response = self.client.patch( + f"/api/projects/{self.team.id}/surveys/{survey.id}/", + data={"end_date": end_date}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + mock_report_user_action.assert_called_once_with( + self.user, + "survey stopped", + { + **expected_properties, + "start_date": start_date, + "end_date": end_date, + }, + self.team, + ) + mock_report_user_action.reset_mock() + + # remove the end date / aka resume survey + response = self.client.patch( + f"/api/projects/{self.team.id}/surveys/{survey.id}/", + data={"end_date": None}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + mock_report_user_action.assert_called_once_with( + self.user, + "survey resumed", + { + **expected_properties, + "start_date": start_date, + "end_date": None, + }, + self.team, + ) + @freeze_time("2023-05-01 12:00:00") def test_delete_survey_records_activity(self): survey = Survey.objects.create( diff --git a/posthog/event_usage.py b/posthog/event_usage.py index cf74b59936365..7f0786d8450ad 100644 --- a/posthog/event_usage.py +++ b/posthog/event_usage.py @@ -140,6 +140,8 @@ def report_team_member_invited( current_member_count: int, is_bulk: bool, email_available: bool, + current_url: Optional[str] = None, + session_id: Optional[str] = None, ) -> None: """ Triggered after a user creates an **individual** invite for a new team member. See `report_bulk_invited` @@ -154,11 +156,17 @@ def report_team_member_invited( "is_bulk": is_bulk, } + inviting_user_properties = { + **properties, + "$current_url": current_url, + "$session_id": session_id, + } + # Report for inviting user posthoganalytics.capture( inviting_user.distinct_id, - "team invite executed", - properties=properties, + "team member invited", + properties=inviting_user_properties, groups=groups(inviting_user.current_organization, inviting_user.current_team), ) @@ -178,6 +186,8 @@ def report_bulk_invited( current_invite_count: int, current_member_count: int, email_available: bool, + current_url: Optional[str] = None, + session_id: Optional[str] = None, ) -> None: """ Triggered after a user bulk creates invites for another user. @@ -191,6 +201,8 @@ def report_bulk_invited( "current_invite_count": current_invite_count, # number of invites including this set "current_member_count": current_member_count, "email_available": email_available, + "$current_url": current_url, + "$session_id": session_id, }, groups=groups(user.current_organization, user.current_team), ) diff --git a/posthog/schema.py b/posthog/schema.py index a5d0f7dd6e952..abfbb3e62f7f2 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -4835,6 +4835,7 @@ class RecordingsQuery(BaseModel): ] = None response: Optional[RecordingsQueryResponse] = None session_ids: Optional[list[str]] = None + user_modified_filters: Optional[dict[str, Any]] = None class RetentionQuery(BaseModel): diff --git a/posthog/session_recordings/session_recording_api.py b/posthog/session_recordings/session_recording_api.py index 3e811255f93d5..181a3433a8add 100644 --- a/posthog/session_recordings/session_recording_api.py +++ b/posthog/session_recordings/session_recording_api.py @@ -1,59 +1,64 @@ +import json import os import time +from collections.abc import Generator from contextlib import contextmanager -from datetime import datetime, timedelta, UTC -from prometheus_client import Histogram -import json +from datetime import UTC, datetime, timedelta from typing import Any, cast -from collections.abc import Generator - -from django.conf import settings import posthoganalytics import requests +from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.core.cache import cache -from django.http import JsonResponse, HttpResponse +from django.http import HttpResponse, JsonResponse from drf_spectacular.utils import extend_schema -from loginas.utils import is_impersonated_session +from prometheus_client import Counter, Histogram from rest_framework import exceptions, request, serializers, viewsets -from posthog.api.utils import action +from rest_framework.mixins import UpdateModelMixin from rest_framework.renderers import JSONRenderer from rest_framework.response import Response from rest_framework.utils.encoders import JSONEncoder +from ee.session_recordings.ai.error_clustering import error_clustering +from ee.session_recordings.ai.similar_recordings import similar_recordings +from ee.session_recordings.session_summary.summarize_session import summarize_recording from posthog.api.person import MinimalPersonSerializer from posthog.api.routing import TeamAndOrgViewSetMixin -from posthog.api.utils import safe_clickhouse_string -from posthog.auth import SharingAccessTokenAuthentication +from posthog.api.utils import action, safe_clickhouse_string +from posthog.auth import PersonalAPIKeyAuthentication, SharingAccessTokenAuthentication from posthog.cloud_utils import is_cloud from posthog.constants import SESSION_RECORDINGS_FILTER_IDS -from posthog.models import User, Team +from posthog.event_usage import report_user_action +from posthog.models import Team, User from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter from posthog.models.person.person import PersonDistinctId -from posthog.schema import QueryTiming, HogQLQueryModifiers +from posthog.rate_limit import ( + ClickHouseBurstRateThrottle, + ClickHouseSustainedRateThrottle, + PersonalApiKeyRateThrottle, +) +from posthog.schema import HogQLQueryModifiers, QueryTiming from posthog.session_recordings.models.session_recording import SessionRecording from posthog.session_recordings.models.session_recording_event import ( SessionRecordingViewed, ) - from posthog.session_recordings.queries.session_recording_list_from_filters import ( - SessionRecordingListFromFilters, ReplayFiltersEventsSubQuery, + SessionRecordingListFromFilters, ) from posthog.session_recordings.queries.session_recording_properties import ( SessionRecordingProperties, ) -from posthog.rate_limit import ClickHouseBurstRateThrottle, ClickHouseSustainedRateThrottle, PersonalApiKeyRateThrottle from posthog.session_recordings.queries.session_replay_events import SessionReplayEvents -from posthog.session_recordings.realtime_snapshots import get_realtime_snapshots, publish_subscription -from ee.session_recordings.session_summary.summarize_session import summarize_recording -from ee.session_recordings.ai.similar_recordings import similar_recordings -from ee.session_recordings.ai.error_clustering import error_clustering -from posthog.session_recordings.snapshots.convert_legacy_snapshots import convert_original_version_lts_recording +from posthog.session_recordings.realtime_snapshots import ( + get_realtime_snapshots, + publish_subscription, +) +from posthog.session_recordings.snapshots.convert_legacy_snapshots import ( + convert_original_version_lts_recording, +) from posthog.storage import object_storage -from prometheus_client import Counter -from posthog.auth import PersonalAPIKeyAuthentication SNAPSHOTS_BY_PERSONAL_API_KEY_COUNTER = Counter( "snapshots_personal_api_key_counter", @@ -222,6 +227,18 @@ class SessionRecordingSourcesSerializer(serializers.Serializer): snapshots = serializers.ListField(required=False) +class SessionRecordingUpdateSerializer(serializers.Serializer): + viewed = serializers.BooleanField(required=False) + analyzed = serializers.BooleanField(required=False) + player_metadata = serializers.JSONField(required=False) + durations = serializers.JSONField(required=False) + + def validate(self, data): + if not data.get("viewed") and not data.get("analyzed"): + raise serializers.ValidationError("At least one of 'viewed' or 'analyzed' must be provided.") + return data + + def list_recordings_response( filter: SessionRecordingsFilter, request: request.Request, serializer_context: dict[str, Any] ) -> Response: @@ -277,7 +294,7 @@ class SnapshotsSustainedRateThrottle(PersonalApiKeyRateThrottle): # NOTE: Could we put the sharing stuff in the shared mixin :thinking: -class SessionRecordingViewSet(TeamAndOrgViewSetMixin, viewsets.GenericViewSet): +class SessionRecordingViewSet(TeamAndOrgViewSetMixin, viewsets.GenericViewSet, UpdateModelMixin): scope_object = "session_recording" scope_object_read_actions = ["list", "retrieve", "snapshots"] throttle_classes = [ClickHouseBurstRateThrottle, ClickHouseSustainedRateThrottle] @@ -303,6 +320,7 @@ def safely_get_object(self, queryset) -> SessionRecording: def list(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: filter = SessionRecordingsFilter(request=request, team=self.team) + self._maybe_report_recording_list_filters_changed(request) return list_recordings_response(filter, request, self.get_serializer_context()) @extend_schema( @@ -354,14 +372,67 @@ def retrieve(self, request: request.Request, *args: Any, **kwargs: Any) -> Respo recording.load_person() - if not request.user.is_anonymous: - save_viewed = request.GET.get("save_view") is not None and not is_impersonated_session(request) - recording.check_viewed_for_user(request.user, save_viewed=save_viewed) - serializer = self.get_serializer(recording) return Response(serializer.data) + def update(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: + recording = self.get_object() + loaded = recording.load_metadata() + + if recording is None or recording.deleted or not loaded: + raise exceptions.NotFound("Recording not found") + + serializer = SessionRecordingUpdateSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + current_url = request.headers.get("Referer") + session_id = request.headers.get("X-Posthog-Session-Id") + durations = serializer.validated_data.get("durations", {}) + player_metadata = serializer.validated_data.get("player_metadata", {}) + + event_properties = { + "$current_url": current_url, + "$session_id": session_id, + "snapshots_load_time": durations.get("snapshots"), + "metadata_load_time": durations.get("metadata"), + "events_load_time": durations.get("events"), + "first_paint_load_time": durations.get("firstPaint"), + "duration": player_metadata.get("duration"), + "recording_id": player_metadata.get("sessionRecordingId"), + "start_time": player_metadata.get("start"), + "end_time": player_metadata.get("end"), + "page_change_events_length": player_metadata.get("pageChangeEventsLength"), + "recording_width": player_metadata.get("recordingWidth"), + "load_time": durations.get( + "firstPaint", 0 + ), # TODO: DEPRECATED field. Keep around so dashboards don't break + # older recordings did not store this and so "null" is equivalent to web + # but for reporting we want to distinguish between not loaded and no value to load + "snapshot_source": player_metadata.get("snapshotSource", "unknown"), + } + user: User | None | AnonymousUser = request.user + + if isinstance(user, User) and not user.is_anonymous: + if "viewed" in serializer.validated_data: + recording.check_viewed_for_user(user, save_viewed=True) + report_user_action( + user=user, + event="recording viewed", + properties=event_properties, + team=self.team, + ) + + if "analyzed" in serializer.validated_data: + report_user_action( + user=user, + event="recording analyzed", + properties=event_properties, + team=self.team, + ) + + return Response({"success": True}) + def destroy(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: recording = self.get_object() @@ -446,6 +517,31 @@ def snapshots(self, request: request.Request, **kwargs): else: raise exceptions.ValidationError("Invalid source must be one of [realtime, blob]") + def _maybe_report_recording_list_filters_changed(self, request: request.Request): + """ + If the applied filters were modified by the user, capture only the partial filters + applied (not the full filters object, since that's harder to search through in event props). + Take each key from the filter and change it to `partial_filter_chosen_{key}` + """ + user_modified_filters = request.GET.get("user_modified_filters") + if user_modified_filters: + user_modified_filters_obj = json.loads(user_modified_filters) + partial_filters = { + f"partial_filter_chosen_{key}": value for key, value in user_modified_filters_obj.items() + } + current_url = request.headers.get("Referer") + session_id = request.headers.get("X-POSTHOG-SESSION-ID") + + posthoganalytics.capture( + str(cast(User, request.user).distinct_id), + "recording list filters changed", + { + "$current_url": current_url, + "$session_id": session_id, + **partial_filters, + }, + ) + def _gather_session_recording_sources(self, recording: SessionRecording) -> Response: might_have_realtime = True newest_timestamp = None diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index 46457047cae15..7e6cf8e929807 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -1,40 +1,40 @@ import json import time import uuid -from datetime import datetime, timedelta, UTC -from unittest.mock import ANY, patch, MagicMock, call -from urllib.parse import urlencode +from datetime import UTC, datetime, timedelta from typing import cast +from unittest.mock import ANY, MagicMock, call, patch +from urllib.parse import urlencode -from parameterized import parameterized from dateutil.parser import parse from dateutil.relativedelta import relativedelta from django.utils.timezone import now from freezegun import freeze_time +from parameterized import parameterized from rest_framework import status -from posthog.session_recordings.models.session_recording_event import ( - SessionRecordingViewed, -) from posthog.api.test.test_team import create_team from posthog.constants import SESSION_RECORDINGS_FILTER_IDS from posthog.models import Organization, Person, SessionRecording from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter +from posthog.models.property import Property from posthog.models.team import Team +from posthog.session_recordings.models.session_recording_event import ( + SessionRecordingViewed, +) from posthog.session_recordings.queries.test.session_replay_sql import ( produce_replay_summary, ) -from posthog.models.property import Property +from posthog.session_recordings.test import setup_stream_from from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, + FuzzyInt, QueryMatchingTest, + _create_event, flush_persons_and_events, snapshot_postgres_queries, - FuzzyInt, - _create_event, ) -from posthog.session_recordings.test import setup_stream_from class TestSessionRecordings(APIBaseTest, ClickhouseTestMixin, QueryMatchingTest): @@ -169,13 +169,15 @@ def test_can_list_recordings_even_when_the_person_has_multiple_distinct_ids(self assert results_[0]["distinct_id"] == "user2" assert results_[1]["distinct_id"] in twelve_distinct_ids + @patch("posthoganalytics.capture") @patch("posthog.session_recordings.session_recording_api.SessionRecordingListFromFilters") - def test_console_log_filters_are_correctly_passed_to_listing(self, mock_summary_lister): + def test_console_log_filters_are_correctly_passed_to_listing(self, mock_summary_lister, mock_capture): mock_summary_lister.return_value.run.return_value = ([], False) params_string = urlencode( { - "console_log_filters": '[{"key": "console_log_level", "value": ["warn", "error"], "operator": "exact", "type": "recording"}]' + "console_log_filters": '[{"key": "console_log_level", "value": ["warn", "error"], "operator": "exact", "type": "recording"}]', + "user_modified_filters": '{"my_filter": "something"}', } ) self.client.get(f"/api/projects/{self.team.id}/session_recordings?{params_string}") @@ -184,6 +186,15 @@ def test_console_log_filters_are_correctly_passed_to_listing(self, mock_summary_ filter_passed_to_mock: SessionRecordingsFilter = mock_summary_lister.call_args_list[0].kwargs["filter"] console_filter = cast(Property, filter_passed_to_mock.console_log_filters.values[0]) assert console_filter.value == ["warn", "error"] + assert mock_capture.call_args_list[0] == call( + self.user.distinct_id, + "recording list filters changed", + { + "$current_url": ANY, + "$session_id": ANY, + "partial_filter_chosen_my_filter": "something", + }, + ) @snapshot_postgres_queries def test_listing_recordings_is_not_nplus1_for_persons(self): @@ -347,20 +358,104 @@ def test_setting_viewed_state_of_session_recording(self): assert response_data["results"][0]["viewed"] is False assert response_data["results"][0]["id"] == "1" - # can set it to viewed - save_as_viewed_response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/1?save_view=True") - assert save_as_viewed_response.status_code == 200 + @patch("posthoganalytics.capture") + def test_update_session_recording_viewed(self, mock_capture: MagicMock): + session_id = "test_update_viewed_state" + base_time = (now() - relativedelta(days=1)).replace(microsecond=0) + Person.objects.create( + team=self.team, + distinct_ids=["u1"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, + ) + base_time = (now() - relativedelta(days=1)).replace(microsecond=0) + + produce_replay_summary( + session_id=session_id, + team_id=self.team.pk, + first_timestamp=base_time.isoformat(), + last_timestamp=base_time.isoformat(), + distinct_id="u1", + first_url="https://example.io/home", + click_count=2, + keypress_count=2, + mouse_activity_count=2, + active_milliseconds=50 * 1000 * 0.5, + ) + + # Verify initial state + response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/{session_id}") + assert response.status_code == 200 + assert response.json()["viewed"] is False + + # Update viewed state + update_response = self.client.patch( + f"/api/projects/{self.team.id}/session_recordings/{session_id}", + {"viewed": True}, + ) + assert update_response.status_code == 200 + assert update_response.json()["success"] is True + # Verify updated state + # We don't get the viewed state back in the retrieve endpoint, so we need to list them final_view_response = self.client.get(f"/api/projects/{self.team.id}/session_recordings") response_data = final_view_response.json() - # Make sure the query param sets it to viewed assert response_data["results"][0]["viewed"] is True - assert response_data["results"][0]["id"] == "1" + assert response_data["results"][0]["id"] == "test_update_viewed_state" - response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/1") - response_data = response.json() - # In the metadata response too - self.assertEqual(response_data["viewed"], True) + assert len(mock_capture.call_args_list) == 1 + assert mock_capture.call_args_list[0][0][1] == "recording viewed" + + @patch("posthoganalytics.capture") + def test_update_session_recording_analyzed(self, mock_capture: MagicMock): + session_id = "test_update_analyzed_state" + base_time = (now() - relativedelta(days=1)).replace(microsecond=0) + produce_replay_summary( + session_id=session_id, + team_id=self.team.pk, + first_timestamp=base_time.isoformat(), + last_timestamp=base_time.isoformat(), + distinct_id="u1", + ) + + # Update analyzed state + update_response = self.client.patch( + f"/api/projects/{self.team.id}/session_recordings/{session_id}", + {"analyzed": True}, + ) + assert update_response.status_code == 200 + assert update_response.json()["success"] is True + + # Verify that the appropriate event was reported + assert len(mock_capture.call_args_list) == 1 + assert mock_capture.call_args_list[0][0][1] == "recording analyzed" + + def test_update_session_recording_invalid_data(self): + session_id = "test_update_invalid_data" + base_time = (now() - relativedelta(days=1)).replace(microsecond=0) + produce_replay_summary( + session_id=session_id, + team_id=self.team.pk, + first_timestamp=base_time.isoformat(), + last_timestamp=base_time.isoformat(), + distinct_id="u1", + ) + + # Attempt to update with invalid data + update_response = self.client.patch( + f"/api/projects/{self.team.id}/session_recordings/{session_id}", + {"invalid_field": True}, + ) + assert update_response.status_code == 400 + + def test_update_nonexistent_session_recording(self): + nonexistent_session_id = "nonexistent_session" + + # Attempt to update a non-existent session recording + update_response = self.client.patch( + f"/api/projects/{self.team.id}/session_recordings/{nonexistent_session_id}", + {"viewed": True}, + ) + assert update_response.status_code == 404 def test_get_single_session_recording_metadata(self): with freeze_time("2023-01-01T12:00:00.000Z"):