diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1a9478a..a8e5e3e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.21.0" + ".": "1.22.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 10776c8..43ea610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [1.22.0](https://github.com/dograh-hq/dograh/compare/dograh-v1.21.0...dograh-v1.22.0) (2026-04-10) + + +### Features + +* add full document mode in knowledge base ([87c8c5e](https://github.com/dograh-hq/dograh/commit/87c8c5e2c81815da30a830d0b8196a850e2102e0)) +* add posthog events ([#231](https://github.com/dograh-hq/dograh/issues/231)) ([3f19a16](https://github.com/dograh-hq/dograh/commit/3f19a16e7f9efb710c533046f68d9be112be0c0f)) +* add recording audio option in tool and node transitions ([#232](https://github.com/dograh-hq/dograh/issues/232)) ([7c24505](https://github.com/dograh-hq/dograh/commit/7c245051d2ea6b04d31173075cbabc101431835b)) + + +### Bug Fixes + +* render prompt template for variable extraction ([8b3dc02](https://github.com/dograh-hq/dograh/commit/8b3dc02722f9743871e33b84656cae7498adc53e)) + ## [1.21.0](https://github.com/dograh-hq/dograh/compare/dograh-v1.20.0...dograh-v1.21.0) (2026-04-08) diff --git a/api/constants.py b/api/constants.py index 2bc81ac..ad77800 100644 --- a/api/constants.py +++ b/api/constants.py @@ -51,6 +51,10 @@ S3_REGION = os.environ.get("S3_REGION", "us-east-1") # Sentry configuration SENTRY_DSN = os.getenv("SENTRY_DSN") +# PostHog configuration +POSTHOG_API_KEY = os.getenv("POSTHOG_API_KEY") +POSTHOG_HOST = os.getenv("POSTHOG_HOST", "https://us.i.posthog.com") + ENABLE_ARI_STASIS = os.getenv("ENABLE_ARI_STASIS", "false").lower() == "true" SERIALIZE_LOG_OUTPUT = os.getenv("SERIALIZE_LOG_OUTPUT", "false").lower() == "true" diff --git a/api/enums.py b/api/enums.py index 95d3c62..95915ad 100644 --- a/api/enums.py +++ b/api/enums.py @@ -140,3 +140,18 @@ class ToolStatus(Enum): ACTIVE = "active" # Tool is available for use ARCHIVED = "archived" # Tool is soft-deleted DRAFT = "draft" # Tool is being configured (not ready for use) + + +class PostHogEvent(str, Enum): + """PostHog event names — backend events only.""" + + WORKFLOW_CREATED = "workflow_created" + WORKFLOW_PUBLISHED = "workflow_published" + WORKFLOW_DUPLICATED = "workflow_duplicated" + CALL_STARTED = "call_started" + CALL_COMPLETED = "call_completed" + CALL_FAILED = "call_failed" + TELEPHONY_CONFIGURED = "telephony_configured" + KNOWLEDGE_BASE_CREATED = "knowledge_base_created" + TOOL_CREATED = "tool_created" + AGENT_EMBEDDED = "agent_embedded" diff --git a/api/pyproject.toml b/api/pyproject.toml index f68fb34..4e327d1 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,5 +1,5 @@ [project] name = "dograh-api" -version = "1.21.0" +version = "1.22.0" description = "Backend API for Dograh voice AI platform" requires-python = ">=3.12" diff --git a/api/requirements.txt b/api/requirements.txt index 8852613..e45dbe4 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -17,3 +17,4 @@ docling[rapidocr]==2.68.0 pgvector==0.4.2 bcrypt==5.0.0 email-validator==2.3.0 +posthog==3.24.0 diff --git a/api/routes/auth.py b/api/routes/auth.py index 9f22ee5..137ff7b 100644 --- a/api/routes/auth.py +++ b/api/routes/auth.py @@ -60,6 +60,7 @@ async def signup(request: SignupRequest): email=user.email, name=request.name, organization_id=organization.id, + provider_id=user.provider_id, ), ) @@ -84,6 +85,7 @@ async def login(request: LoginRequest): id=user.id, email=user.email, organization_id=user.selected_organization_id, + provider_id=user.provider_id, ), ) @@ -94,4 +96,5 @@ async def get_current_user(user: UserModel = Depends(get_user)): id=user.id, email=user.email, organization_id=user.selected_organization_id, + provider_id=user.provider_id, ) diff --git a/api/routes/knowledge_base.py b/api/routes/knowledge_base.py index 598b6fa..e05c4cd 100644 --- a/api/routes/knowledge_base.py +++ b/api/routes/knowledge_base.py @@ -7,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query from loguru import logger from api.db import db_client +from api.enums import PostHogEvent from api.schemas.knowledge_base import ( ChunkSearchRequestSchema, ChunkSearchResponseSchema, @@ -17,6 +18,7 @@ from api.schemas.knowledge_base import ( ProcessDocumentRequestSchema, ) from api.services.auth.depends import get_user +from api.services.posthog_client import capture_event from api.services.storage import storage_fs from api.tasks.arq import enqueue_job from api.tasks.function_names import FunctionNames @@ -142,6 +144,18 @@ async def process_document( f"with OpenAI embeddings, org {user.selected_organization_id}" ) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.KNOWLEDGE_BASE_CREATED, + properties={ + "document_id": document.id, + "document_uuid": str(request.document_uuid), + "filename": filename, + "retrieval_mode": request.retrieval_mode, + "organization_id": user.selected_organization_id, + }, + ) + return DocumentResponseSchema( id=document.id, document_uuid=request.document_uuid, diff --git a/api/routes/organization.py b/api/routes/organization.py index 854fab1..f35ef0a 100644 --- a/api/routes/organization.py +++ b/api/routes/organization.py @@ -6,7 +6,7 @@ from pydantic import BaseModel from api.constants import DEFAULT_CAMPAIGN_RETRY_CONFIG, DEFAULT_ORG_CONCURRENCY_LIMIT from api.db import db_client from api.db.models import UserModel -from api.enums import OrganizationConfigurationKey +from api.enums import OrganizationConfigurationKey, PostHogEvent from api.schemas.telephony_config import ( ARIConfigurationRequest, ARIConfigurationResponse, @@ -24,6 +24,7 @@ from api.schemas.telephony_config import ( ) from api.services.auth.depends import get_user from api.services.configuration.masking import is_mask_of, mask_key +from api.services.posthog_client import capture_event from api.services.worker_sync.manager import get_worker_sync_manager from api.services.worker_sync.protocol import WorkerSyncEventType @@ -257,6 +258,16 @@ async def save_telephony_configuration( config_value, ) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.TELEPHONY_CONFIGURED, + properties={ + "provider": request.provider, + "phone_number_count": len(request.from_numbers), + "organization_id": user.selected_organization_id, + }, + ) + return {"message": "Telephony configuration saved successfully"} diff --git a/api/routes/tool.py b/api/routes/tool.py index f3caa94..202772f 100644 --- a/api/routes/tool.py +++ b/api/routes/tool.py @@ -9,8 +9,9 @@ from pydantic import BaseModel, Field, field_validator from api.db import db_client from api.db.models import UserModel -from api.enums import ToolCategory, ToolStatus +from api.enums import PostHogEvent, ToolCategory, ToolStatus from api.services.auth.depends import get_user +from api.services.posthog_client import capture_event router = APIRouter(prefix="/tools") @@ -342,6 +343,16 @@ async def create_tool( icon_color=request.icon_color, ) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.TOOL_CREATED, + properties={ + "tool_name": request.name, + "tool_category": request.category, + "organization_id": user.selected_organization_id, + }, + ) + return build_tool_response(tool) diff --git a/api/routes/webrtc_signaling.py b/api/routes/webrtc_signaling.py index 0be108a..6de2bb4 100644 --- a/api/routes/webrtc_signaling.py +++ b/api/routes/webrtc_signaling.py @@ -281,7 +281,12 @@ class SignalingManager: # Start pipeline in background asyncio.create_task( run_pipeline_smallwebrtc( - pc, workflow_id, workflow_run_id, user.id, call_context_vars + pc, + workflow_id, + workflow_run_id, + user.id, + call_context_vars, + user_provider_id=str(user.provider_id), ) ) diff --git a/api/routes/workflow.py b/api/routes/workflow.py index 58733d6..1b3250b 100644 --- a/api/routes/workflow.py +++ b/api/routes/workflow.py @@ -13,7 +13,7 @@ from api.constants import DEPLOYMENT_MODE from api.db import db_client from api.db.models import UserModel from api.db.workflow_template_client import WorkflowTemplateClient -from api.enums import CallType, StorageBackend +from api.enums import CallType, PostHogEvent, StorageBackend from api.schemas.workflow import WorkflowRunResponseSchema from api.services.auth.depends import get_user from api.services.configuration.check_validity import UserConfigurationValidator @@ -23,6 +23,7 @@ from api.services.configuration.masking import ( ) from api.services.configuration.resolve import resolve_effective_config from api.services.mps_service_key_client import mps_service_key_client +from api.services.posthog_client import capture_event from api.services.storage import storage_fs from api.services.workflow.dto import ReactFlowDTO from api.services.workflow.duplicate import duplicate_workflow @@ -287,6 +288,17 @@ async def create_workflow( user.selected_organization_id, ) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.WORKFLOW_CREATED, + properties={ + "workflow_id": workflow.id, + "workflow_name": workflow.name, + "source": "direct", + "organization_id": user.selected_organization_id, + }, + ) + # Sync agent triggers if workflow definition contains any if request.workflow_definition: trigger_paths = extract_trigger_paths(request.workflow_definition) @@ -365,6 +377,19 @@ async def create_workflow_from_template( organization_id=user.selected_organization_id, ) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.WORKFLOW_CREATED, + properties={ + "workflow_id": workflow.id, + "workflow_name": workflow.name, + "source": "template", + "call_type": request.call_type, + "use_case": request.use_case, + "organization_id": user.selected_organization_id, + }, + ) + # Sync agent triggers if workflow definition contains any if workflow_def: trigger_paths = extract_trigger_paths(workflow_def) @@ -569,6 +594,16 @@ async def publish_workflow( except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.WORKFLOW_PUBLISHED, + properties={ + "workflow_id": workflow_id, + "version_number": published.version_number, + "organization_id": user.selected_organization_id, + }, + ) + return { "id": published.id, "version_number": published.version_number, @@ -787,6 +822,18 @@ async def duplicate_workflow_endpoint( organization_id=user.selected_organization_id, user_id=user.id, ) + + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.WORKFLOW_DUPLICATED, + properties={ + "workflow_id": workflow.id, + "workflow_name": workflow.name, + "source_workflow_id": workflow_id, + "organization_id": user.selected_organization_id, + }, + ) + return { "id": workflow.id, "name": workflow.name, diff --git a/api/routes/workflow_embed.py b/api/routes/workflow_embed.py index 4b7823e..4923ec3 100644 --- a/api/routes/workflow_embed.py +++ b/api/routes/workflow_embed.py @@ -9,7 +9,9 @@ from pydantic import BaseModel from api.constants import BACKEND_API_ENDPOINT, ENVIRONMENT, UI_APP_URL from api.db import db_client from api.db.models import EmbedTokenModel, UserModel +from api.enums import PostHogEvent from api.services.auth.depends import get_user +from api.services.posthog_client import capture_event router = APIRouter(prefix="/workflow") @@ -103,6 +105,17 @@ async def create_or_update_embed_token( expires_at=expires_at, ) + capture_event( + distinct_id=str(user.provider_id), + event=PostHogEvent.AGENT_EMBEDDED, + properties={ + "workflow_id": workflow_id, + "is_new_token": len(existing_tokens) == 0, + "has_domain_restriction": bool(embed_request.allowed_domains), + "organization_id": user.selected_organization_id, + }, + ) + # Generate embed script embed_script = generate_embed_script(token) diff --git a/api/schemas/auth.py b/api/schemas/auth.py index 467940f..3cb53ef 100644 --- a/api/schemas/auth.py +++ b/api/schemas/auth.py @@ -24,6 +24,7 @@ class UserResponse(BaseModel): email: str | None name: str | None = None organization_id: int | None = None + provider_id: str | None = None class AuthResponse(BaseModel): diff --git a/api/services/pipecat/event_handlers.py b/api/services/pipecat/event_handlers.py index 410751f..fe6c769 100644 --- a/api/services/pipecat/event_handlers.py +++ b/api/services/pipecat/event_handlers.py @@ -3,7 +3,7 @@ import asyncio from loguru import logger from api.db import db_client -from api.enums import WorkflowRunState +from api.enums import PostHogEvent, WorkflowRunState from api.services.campaign.circuit_breaker import circuit_breaker from api.services.pipecat.audio_config import AudioConfig from api.services.pipecat.audio_playback import play_audio, play_audio_loop @@ -13,6 +13,7 @@ from api.services.pipecat.in_memory_buffers import ( ) from api.services.pipecat.pipeline_metrics_aggregator import PipelineMetricsAggregator from api.services.pipecat.tracing_config import get_trace_url +from api.services.posthog_client import capture_event from api.services.workflow.pipecat_engine import PipecatEngine from api.tasks.arq import enqueue_job from api.tasks.function_names import FunctionNames @@ -26,6 +27,37 @@ from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor from pipecat.utils.enums import EndTaskReason +async def _capture_call_event( + workflow_run_id: int, + user_provider_id: str | None, + event: str, + extra_properties: dict | None = None, +) -> None: + """Look up workflow_run for call metadata and fire a PostHog event. + Meant to be run via asyncio.create_task() so it never blocks the pipeline.""" + try: + workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id) + properties = { + "workflow_run_id": workflow_run_id, + "workflow_id": workflow_run.workflow_id if workflow_run else None, + "call_type": workflow_run.mode if workflow_run else None, + "call_direction": (workflow_run.initial_context or {}).get( + "direction", "outbound" + ) + if workflow_run + else None, + } + if extra_properties: + properties.update(extra_properties) + capture_event( + distinct_id=user_provider_id, + event=event, + properties=properties, + ) + except Exception: + logger.exception(f"Background PostHog capture failed for '{event}'") + + def register_event_handlers( task: PipelineTask, transport, @@ -37,6 +69,7 @@ def register_event_handlers( audio_config=AudioConfig, pre_call_fetch_task: asyncio.Task | None = None, fetch_recording_audio=None, + user_provider_id: str | None = None, ): """Register all event handlers for transport and task events. @@ -80,6 +113,12 @@ def register_event_handlers( ): ready_state["initial_response_triggered"] = True + asyncio.create_task( + _capture_call_event( + workflow_run_id, user_provider_id, PostHogEvent.CALL_STARTED + ) + ) + # Wait for pre-call fetch if in progress, playing ringer meanwhile if pre_call_fetch_task is not None: if not pre_call_fetch_task.done(): @@ -193,6 +232,14 @@ def register_event_handlers( await circuit_breaker.record_and_evaluate( campaign_id=workflow_run.campaign_id, is_failure=True ) + asyncio.create_task( + _capture_call_event( + workflow_run_id, + user_provider_id, + PostHogEvent.CALL_FAILED, + extra_properties={"error_reason": "pipeline_error"}, + ) + ) except Exception as e: logger.error(f"Error recording circuit breaker failure: {e}", exc_info=True) @@ -301,6 +348,12 @@ def register_event_handlers( state=WorkflowRunState.COMPLETED.value, ) + asyncio.create_task( + _capture_call_event( + workflow_run_id, user_provider_id, PostHogEvent.CALL_COMPLETED + ) + ) + # Save real-time feedback logs to workflow run if not in_memory_logs_buffer.is_empty: try: diff --git a/api/services/pipecat/run_pipeline.py b/api/services/pipecat/run_pipeline.py index 1463f26..b9ff9a3 100644 --- a/api/services/pipecat/run_pipeline.py +++ b/api/services/pipecat/run_pipeline.py @@ -483,6 +483,7 @@ async def run_pipeline_smallwebrtc( workflow_run_id: int, user_id: int, call_context_vars: dict = {}, + user_provider_id: str | None = None, ) -> None: """Run pipeline for WebRTC connections""" logger.debug( @@ -524,6 +525,7 @@ async def run_pipeline_smallwebrtc( user_id, call_context_vars=call_context_vars, audio_config=audio_config, + user_provider_id=user_provider_id, ) @@ -534,6 +536,7 @@ async def _run_pipeline( user_id: int, call_context_vars: dict = {}, audio_config: AudioConfig = None, + user_provider_id: str | None = None, ) -> None: """ Run the pipeline with the given transport and configuration @@ -964,7 +967,10 @@ async def _run_pipeline( in_memory_logs_buffer, user_context_aggregator, assistant_context_aggregator ) - # Register event handlers + # Register event handlers — resolve provider_id for PostHog tracking + if not user_provider_id: + user_obj = await db_client.get_user_by_id(user_id) + user_provider_id = str(user_obj.provider_id) if user_obj else None in_memory_audio_buffer = register_event_handlers( task, transport, @@ -976,6 +982,7 @@ async def _run_pipeline( audio_config=audio_config, pre_call_fetch_task=pre_call_fetch_task, fetch_recording_audio=fetch_audio, + user_provider_id=user_provider_id, ) register_audio_data_handler(audio_buffer, workflow_run_id, in_memory_audio_buffer) diff --git a/api/services/posthog_client.py b/api/services/posthog_client.py new file mode 100644 index 0000000..d9b262b --- /dev/null +++ b/api/services/posthog_client.py @@ -0,0 +1,31 @@ +from loguru import logger +from posthog import Posthog + +from api.constants import POSTHOG_API_KEY, POSTHOG_HOST + +_posthog_client: Posthog | None = None + + +def get_posthog() -> Posthog | None: + """Return the lazily-initialised PostHog client, or None if not configured.""" + global _posthog_client + if _posthog_client is None and POSTHOG_API_KEY: + _posthog_client = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST) + return _posthog_client + + +def capture_event( + distinct_id: str, + event: str, + properties: dict | None = None, +) -> None: + """Fire a PostHog event. Silently no-ops if PostHog is not configured.""" + client = get_posthog() + if not client: + return + try: + client.capture( + distinct_id=distinct_id, event=event, properties=properties or {} + ) + except Exception: + logger.exception(f"Failed to send PostHog event '{event}'") diff --git a/ui/package-lock.json b/ui/package-lock.json index 39c9484..07c1430 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "ui", - "version": "1.20.0", + "version": "1.21.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ui", - "version": "1.20.0", + "version": "1.21.0", "dependencies": { "@dagrejs/dagre": "^1.1.4", "@nangohq/frontend": "^0.69.47", @@ -717,7 +717,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -919,6 +918,7 @@ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "license": "MIT", + "peer": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1033,6 +1033,7 @@ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -1051,13 +1052,15 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emotion/babel-plugin/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -1067,6 +1070,7 @@ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", "license": "MIT", + "peer": true, "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", @@ -1079,19 +1083,22 @@ "version": "0.9.2", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emotion/memoize": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emotion/react": { "version": "11.14.0", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1116,6 +1123,7 @@ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", "license": "MIT", + "peer": true, "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", @@ -1128,19 +1136,22 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emotion/unitless": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", "license": "MIT", + "peer": true, "peerDependencies": { "react": ">=16.8.0" } @@ -1149,13 +1160,15 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.7", @@ -1798,7 +1811,6 @@ "integrity": "sha512-lk5C+WKl5yqEmliQihEyhX/jNcWlAykTSEqkDeKa9xSq5YDAzOFvx7oos8YTqiIzdc4TemtlEaB8Rns7+8A0qg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@hey-api/codegen-core": "0.7.4", "@hey-api/json-schema-ref-parser": "1.3.1", @@ -2444,6 +2456,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -2702,7 +2715,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -2753,7 +2765,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz", "integrity": "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/api-logs": "0.57.2", "@types/shimmer": "^1.2.0", @@ -3425,7 +3436,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=14" } @@ -8133,7 +8143,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -10017,7 +10026,6 @@ "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz", "integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.16" } @@ -10429,6 +10437,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -10439,6 +10448,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -10491,7 +10501,8 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/pg": { "version": "8.6.1", @@ -10518,7 +10529,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.0.tgz", "integrity": "sha512-UaicktuQI+9UKyA4njtDOGBD/67t8YEBt2xdfqu8+gP9hqPUPsiXlNPcpS2gVdjmis5GKPG3fCxbQLVgxsQZ8w==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -10529,7 +10539,6 @@ "integrity": "sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -10539,6 +10548,7 @@ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "*" } @@ -11061,6 +11071,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -11070,25 +11081,29 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -11099,13 +11114,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -11118,6 +11135,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "license": "MIT", + "peer": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -11127,6 +11145,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -11135,13 +11154,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -11158,6 +11179,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -11171,6 +11193,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -11183,6 +11206,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -11197,6 +11221,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "license": "MIT", + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -11212,13 +11237,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@xyflow/react": { "version": "12.9.2", @@ -11285,7 +11312,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -11307,6 +11333,7 @@ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=10.13.0" }, @@ -11358,6 +11385,7 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "license": "MIT", + "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -11375,6 +11403,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -11390,7 +11419,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/ansi-colors": { "version": "4.1.3", @@ -11719,6 +11749,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -11846,7 +11877,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -12050,6 +12080,7 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=6.0" } @@ -12320,6 +12351,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "license": "MIT", + "peer": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -12491,7 +12523,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -12843,6 +12874,7 @@ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -12929,6 +12961,7 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "license": "MIT", + "peer": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -12937,7 +12970,8 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/es-abstract": { "version": "1.23.9", @@ -13055,7 +13089,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/es-object-atoms": { "version": "1.1.1", @@ -13205,7 +13240,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -13379,7 +13413,6 @@ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -13667,6 +13700,7 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.x" } @@ -13772,7 +13806,8 @@ "url": "https://opencollective.com/fastify" } ], - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/fast-xml-builder": { "version": "1.1.4", @@ -13854,7 +13889,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/find-up": { "version": "5.0.0", @@ -14140,7 +14176,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "peer": true }, "node_modules/globals": { "version": "14.0.0", @@ -14351,7 +14388,6 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -14961,6 +14997,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -14975,6 +15012,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -15064,7 +15102,8 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-schema": { "version": "0.4.0", @@ -15402,13 +15441,15 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/loader-runner": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=6.11.5" }, @@ -15488,13 +15529,15 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/merge2": { "version": "1.4.1", @@ -15631,14 +15674,14 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/next": { "version": "15.5.14", "resolved": "https://registry.npmjs.org/next/-/next-15.5.14.tgz", "integrity": "sha512-M6S+4JyRjmKic2Ssm7jHUPkE6YUJ6lv4507jprsSZLulubz0ihO2E+S4zmQK3JZ2ov81JrugukKU4Tz0ivgqqQ==", "license": "MIT", - "peer": true, "dependencies": { "@next/env": "15.5.14", "@swc/helpers": "0.5.15", @@ -16066,6 +16109,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -16140,6 +16184,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -16573,7 +16618,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16604,7 +16648,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -16631,7 +16674,6 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.72.1.tgz", "integrity": "sha512-RhwBoy2ygeVZje+C+bwJ8g0NjTdBmDlJvAUHTxRjTmSUKPYsKfMphkS2sgEMotsY03bP358yEYlnUeZy//D9Ig==", "license": "MIT", - "peer": true, "engines": { "node": ">=18.0.0" }, @@ -16656,15 +16698,13 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-redux": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -16804,6 +16844,7 @@ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -16869,8 +16910,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -16908,7 +16948,8 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", @@ -16945,6 +16986,7 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -17029,7 +17071,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -17201,6 +17242,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "license": "MIT", + "peer": true, "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -17237,6 +17279,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -17248,7 +17291,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/secure-json-parse": { "version": "4.0.0", @@ -17804,7 +17848,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/supports-color": { "version": "7.2.0", @@ -17844,8 +17889,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.1.tgz", "integrity": "sha512-QNbdmeS979Efzim2g/bEvfuh+fTcIdp1y7gA+sb6OYSW74rt7Cr7M78AKdf6HqWT3d5AiTb7SwTT3sLQxr4/qw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -17874,6 +17918,7 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -17892,6 +17937,7 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", @@ -17924,7 +17970,8 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/thread-stream": { "version": "3.1.0", @@ -18001,7 +18048,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -18202,7 +18248,6 @@ "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18389,6 +18434,7 @@ "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", "license": "MIT", + "peer": true, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -18475,6 +18521,7 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "license": "MIT", + "peer": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -18500,6 +18547,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -18563,6 +18611,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -18576,6 +18625,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -18753,6 +18803,7 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "license": "ISC", + "peer": true, "engines": { "node": ">= 6" } @@ -18861,7 +18912,6 @@ "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.1.tgz", "integrity": "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==", "license": "MIT", - "peer": true, "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", @@ -18904,7 +18954,6 @@ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz", "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.20.0" }, diff --git a/ui/package.json b/ui/package.json index f6df3b2..694d487 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "ui", - "version": "1.21.0", + "version": "1.22.0", "private": true, "scripts": { "dev": "cross-env NODE_OPTIONS=--enable-source-maps next dev --turbopack", diff --git a/ui/src/app/workflow/[workflowId]/components/RecordingsDialog.tsx b/ui/src/app/workflow/[workflowId]/components/RecordingsDialog.tsx index 8622bf3..645f8fb 100644 --- a/ui/src/app/workflow/[workflowId]/components/RecordingsDialog.tsx +++ b/ui/src/app/workflow/[workflowId]/components/RecordingsDialog.tsx @@ -1,4 +1,5 @@ import { Loader2, Mic, Pause, Play, Square, Trash2Icon, Upload, X } from "lucide-react"; +import posthog from "posthog-js"; import { useCallback, useEffect, useRef, useState } from "react"; import { @@ -28,6 +29,7 @@ import { } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { LANGUAGE_DISPLAY_NAMES } from "@/constants/languages"; +import { PostHogEvent } from "@/constants/posthog-events"; import { useUserConfig } from "@/context/UserConfigContext"; import { useAudioPlayback } from "@/hooks/useAudioPlayback"; @@ -352,6 +354,10 @@ export const RecordingsDialog = ({ const handlePlay = async (rec: RecordingResponseSchema) => { try { await togglePlayback(rec.recording_id, rec.storage_key, rec.storage_backend); + posthog.capture(PostHogEvent.RECORDING_PLAYED, { + recording_id: rec.recording_id, + source: 'recordings_dialog', + }); } catch { setError("Failed to play recording"); } diff --git a/ui/src/app/workflow/[workflowId]/components/WorkflowEditorHeader.tsx b/ui/src/app/workflow/[workflowId]/components/WorkflowEditorHeader.tsx index 1904e69..b923b31 100644 --- a/ui/src/app/workflow/[workflowId]/components/WorkflowEditorHeader.tsx +++ b/ui/src/app/workflow/[workflowId]/components/WorkflowEditorHeader.tsx @@ -3,6 +3,7 @@ import { ReactFlowInstance } from "@xyflow/react"; import { AlertCircle, ArrowLeft, ChevronDown, Copy, Download, Eye, History, LoaderCircle, Menu, MoreVertical, Phone, Rocket } from "lucide-react"; import { useRouter } from "next/navigation"; +import posthog from "posthog-js"; import { useState } from "react"; import { toast } from "sonner"; @@ -26,6 +27,7 @@ import { PopoverTrigger, } from "@/components/ui/popover"; import { useSidebar } from "@/components/ui/sidebar"; +import { PostHogEvent } from "@/constants/posthog-events"; import { WORKFLOW_RUN_MODES } from "@/constants/workflowRunModes"; interface WorkflowEditorHeaderProps { @@ -272,7 +274,13 @@ export const WorkflowEditorHeader = ({ onRun(WORKFLOW_RUN_MODES.SMALL_WEBRTC)} + onClick={() => { + posthog.capture(PostHogEvent.WEB_CALL_INITIATED, { + workflow_id: workflowId, + workflow_name: workflowName, + }); + onRun(WORKFLOW_RUN_MODES.SMALL_WEBRTC); + }} className="text-white hover:bg-[#2a2a2a] cursor-pointer" > diff --git a/ui/src/app/workflow/[workflowId]/hooks/useWorkflowState.ts b/ui/src/app/workflow/[workflowId]/hooks/useWorkflowState.ts index 4e18d9d..8443acf 100644 --- a/ui/src/app/workflow/[workflowId]/hooks/useWorkflowState.ts +++ b/ui/src/app/workflow/[workflowId]/hooks/useWorkflowState.ts @@ -8,6 +8,7 @@ import { } from "@xyflow/react"; import { EdgeChange, NodeChange } from "@xyflow/system"; import { useRouter } from "next/navigation"; +import posthog from "posthog-js"; import { useCallback, useEffect, useRef } from "react"; import { useWorkflowStore } from "@/app/workflow/[workflowId]/stores/workflowStore"; @@ -18,6 +19,7 @@ import { } from "@/client"; import { WorkflowError } from "@/client/types.gen"; import { FlowEdge, FlowNode, NodeType } from "@/components/flow/types"; +import { PostHogEvent } from "@/constants/posthog-events"; import logger from '@/lib/logger'; import { getNextNodeId, getRandomId } from "@/lib/utils"; import { DEFAULT_WORKFLOW_CONFIGURATIONS, WorkflowConfigurations } from "@/types/workflow-configurations"; @@ -290,8 +292,12 @@ export const useWorkflowState = ({ // Use addNodes from ReactFlow instance rfInstance.current.addNodes([newNode]); + posthog.capture(PostHogEvent.WORKFLOW_NODE_ADDED, { + node_type: nodeType, + workflow_id: workflowId, + }); setIsAddNodePanelOpen(false); - }, [nodes, setIsAddNodePanelOpen]); + }, [nodes, setIsAddNodePanelOpen, workflowId]); const handleNameChange = (e: React.ChangeEvent) => { setWorkflowName(e.target.value); diff --git a/ui/src/app/workflow/[workflowId]/page.tsx b/ui/src/app/workflow/[workflowId]/page.tsx index d3e918c..85e5a07 100644 --- a/ui/src/app/workflow/[workflowId]/page.tsx +++ b/ui/src/app/workflow/[workflowId]/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { useParams } from 'next/navigation'; +import posthog from 'posthog-js'; import { useEffect, useMemo, useState } from 'react'; import RenderWorkflow from '@/app/workflow/[workflowId]/RenderWorkflow'; @@ -8,6 +9,7 @@ import { getWorkflowApiV1WorkflowFetchWorkflowIdGet } from '@/client/sdk.gen'; import type { WorkflowResponse } from '@/client/types.gen'; import { FlowEdge, FlowNode } from '@/components/flow/types'; import SpinLoader from '@/components/SpinLoader'; +import { PostHogEvent } from '@/constants/posthog-events'; import { useAuth } from '@/lib/auth'; import logger from '@/lib/logger'; import { DEFAULT_WORKFLOW_CONFIGURATIONS, WorkflowConfigurations } from '@/types/workflow-configurations'; @@ -39,6 +41,10 @@ export default function WorkflowDetailPage() { }); const workflow = response.data; setWorkflow(workflow); + posthog.capture(PostHogEvent.WORKFLOW_EDITOR_OPENED, { + workflow_id: workflow?.id, + workflow_name: workflow?.name, + }); } catch (err) { setError('Failed to fetch workflow'); logger.error(`Error fetching workflow: ${err}`); diff --git a/ui/src/app/workflow/[workflowId]/run/[runId]/page.tsx b/ui/src/app/workflow/[workflowId]/run/[runId]/page.tsx index 4b1dbf4..67f9767 100644 --- a/ui/src/app/workflow/[workflowId]/run/[runId]/page.tsx +++ b/ui/src/app/workflow/[workflowId]/run/[runId]/page.tsx @@ -3,6 +3,7 @@ import { Check, Copy, ExternalLink, FileText, LoaderCircle, Phone, Video } from 'lucide-react'; import Link from 'next/link'; import { useParams, useRouter } from 'next/navigation'; +import posthog from 'posthog-js'; import { useEffect, useRef, useState } from 'react'; import BrowserCall from '@/app/workflow/[workflowId]/run/[runId]/BrowserCall'; @@ -17,6 +18,7 @@ import { OnboardingTooltip } from '@/components/onboarding/OnboardingTooltip'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { Skeleton } from '@/components/ui/skeleton'; +import { PostHogEvent } from '@/constants/posthog-events'; import { WORKFLOW_RUN_MODES } from '@/constants/workflowRunModes'; import { useOnboarding } from '@/context/OnboardingContext'; import { useAuth } from '@/lib/auth'; @@ -114,7 +116,7 @@ export default function WorkflowRunPage() { }, }); setIsLoading(false); - setWorkflowRun({ + const runData = { is_completed: response.data?.is_completed ?? false, transcript_url: response.data?.transcript_url ?? null, recording_url: response.data?.recording_url ?? null, @@ -122,6 +124,14 @@ export default function WorkflowRunPage() { gathered_context: response.data?.gathered_context as Record | null ?? null, logs: response.data?.logs as WorkflowRunLogs | null ?? null, annotations: response.data?.annotations as Record | null ?? null, + }; + setWorkflowRun(runData); + posthog.capture(PostHogEvent.WORKFLOW_RUN_DETAILS_VIEWED, { + workflow_id: Number(workflowId), + run_id: Number(runId), + is_completed: runData.is_completed, + has_recording: !!runData.recording_url, + has_transcript: !!runData.transcript_url, }); }; fetchWorkflowRun(); diff --git a/ui/src/components/MediaPreviewDialog.tsx b/ui/src/components/MediaPreviewDialog.tsx index 3ca8b2f..208dcfb 100644 --- a/ui/src/components/MediaPreviewDialog.tsx +++ b/ui/src/components/MediaPreviewDialog.tsx @@ -1,6 +1,7 @@ 'use client'; import { Headphones, Loader2 } from 'lucide-react'; +import posthog from 'posthog-js'; import { useCallback, useState } from 'react'; import { Button } from '@/components/ui/button'; @@ -12,6 +13,7 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { PostHogEvent } from '@/constants/posthog-events'; import { downloadFile, getSignedUrl } from '@/lib/files'; export function MediaPreviewDialog() { @@ -48,6 +50,11 @@ export function MediaPreviewDialog() { const response = await fetch(transcriptResult); const text = await response.text(); setTranscriptContent(text); + posthog.capture(PostHogEvent.TRANSCRIPT_VIEWED, { + run_id: runId, + source: 'media_preview_dialog', + transcript_length: text.length, + }); } catch (error) { console.error('Error fetching transcript:', error); } @@ -78,7 +85,16 @@ export function MediaPreviewDialog() { )} {!mediaLoading && audioSignedUrl && ( -