diff --git a/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx b/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx index 2d8bba2f256bc..95a525987b8a2 100644 --- a/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx +++ b/frontend/src/scenes/data-warehouse/new/sourceWizardLogic.tsx @@ -6,6 +6,7 @@ import api from 'lib/api' import posthog from 'posthog-js' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' import { Scene } from 'scenes/sceneTypes' +import { teamLogic } from 'scenes/teamLogic' import { urls } from 'scenes/urls' import { @@ -16,6 +17,7 @@ import { manualLinkSources, ManualLinkSourceType, PipelineTab, + ProductKey, SourceConfig, SourceFieldConfig, } from '~/types' @@ -731,6 +733,8 @@ export const sourceWizardLogic = kea([ ['resetTable', 'createTableSuccess'], dataWarehouseSettingsLogic, ['loadSources'], + teamLogic, + ['addProductIntent'], ], }), reducers({ @@ -1129,6 +1133,9 @@ export const sourceWizardLogic = kea([ setManualLinkingProvider: () => { actions.onNext() }, + selectConnector: () => { + actions.addProductIntent({ product_type: ProductKey.DATA_WAREHOUSE, intent_context: 'selected connector' }) + }, })), urlToAction(({ actions }) => ({ '/data-warehouse/:kind/redirect': ({ kind = '' }, searchParams) => { diff --git a/frontend/src/scenes/teamLogic.tsx b/frontend/src/scenes/teamLogic.tsx index 3f6d102270525..0e6754609ca29 100644 --- a/frontend/src/scenes/teamLogic.tsx +++ b/frontend/src/scenes/teamLogic.tsx @@ -145,13 +145,14 @@ export const teamLogic = kea([ resetToken: async () => await api.update(`api/environments/${values.currentTeamId}/reset_token`, {}), addProductIntent: async ({ product_type, + intent_context, }: { product_type: ProductKey intent_context?: string | null }) => await api.update(`api/environments/${values.currentTeamId}/add_product_intent`, { product_type, - intent_context: null, + intent_context: intent_context ?? undefined, }), recordProductIntentOnboardingComplete: async ({ product_type }: { product_type: ProductKey }) => await api.update(`api/environments/${values.currentTeamId}/complete_product_onboarding`, { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 7c0a8acedad00..c67475b085a93 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -544,6 +544,13 @@ export interface TeamType extends TeamBasicType { extra_settings?: Record modifiers?: HogQLQueryModifiers default_modifiers?: HogQLQueryModifiers + product_intents?: ProductIntentType[] +} + +export interface ProductIntentType { + product_type: string + created_at: string + onboarding_completed_at?: string } // This type would be more correct without `Partial`, but it's only used in the shared dashboard/insight diff --git a/posthog/api/team.py b/posthog/api/team.py index 3f47a67791f28..b3456022cbf44 100644 --- a/posthog/api/team.py +++ b/posthog/api/team.py @@ -6,17 +6,17 @@ from django.shortcuts import get_object_or_404 from loginas.utils import is_impersonated_session -from posthog.auth import PersonalAPIKeyAuthentication -from posthog.jwt import PosthogJwtAudience, encode_jwt from rest_framework import exceptions, request, response, serializers, viewsets from rest_framework.permissions import BasePermission, IsAuthenticated from posthog.api.routing import TeamAndOrgViewSetMixin from posthog.api.shared import TeamBasicSerializer from posthog.api.utils import action +from posthog.auth import PersonalAPIKeyAuthentication from posthog.constants import AvailableFeature from posthog.event_usage import report_user_action from posthog.geoip import get_geoip_properties +from posthog.jwt import PosthogJwtAudience, encode_jwt from posthog.models import ProductIntent, Team, User from posthog.models.activity_logging.activity_log import ( Detail, @@ -209,7 +209,9 @@ def get_live_events_token(self, team: Team) -> Optional[str]: ) def get_product_intents(self, obj): - return ProductIntent.objects.filter(team=obj).values("product_type", "created_at", "onboarding_completed_at") + return ProductIntent.objects.filter(team=obj).values( + "product_type", "created_at", "onboarding_completed_at", "updated_at" + ) @staticmethod def validate_session_recording_linked_flag(value) -> dict | None: @@ -580,7 +582,7 @@ def add_product_intent(self, request: request.Request, *args, **kwargs): product_intent.updated_at = datetime.now(tz=UTC) product_intent.save() - if created and isinstance(user, User): + if isinstance(user, User): report_user_action( user, "user showed product intent", @@ -590,6 +592,9 @@ def add_product_intent(self, request: request.Request, *args, **kwargs): "$current_url": current_url, "$session_id": session_id, "intent_context": request.data.get("intent_context"), + "is_first_intent_for_product": created, + "intent_created_at": product_intent.created_at, + "intent_updated_at": product_intent.updated_at, }, team=team, ) @@ -619,6 +624,9 @@ def complete_product_onboarding(self, request: request.Request, *args, **kwargs) "$current_url": current_url, "$session_id": session_id, "intent_context": request.data.get("intent_context"), + "is_first_intent_for_product": created, + "intent_created_at": product_intent.created_at, + "intent_updated_at": product_intent.updated_at, }, team=team, ) @@ -633,6 +641,9 @@ def complete_product_onboarding(self, request: request.Request, *args, **kwargs) "product_key": product_type, "$current_url": current_url, "$session_id": session_id, + "intent_context": request.data.get("intent_context"), + "intent_created_at": product_intent.created_at, + "intent_updated_at": product_intent.updated_at, }, team=team, )