mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-31 19:45:15 +02:00
feat(automations): enhance tracking for automation lifecycle events
- Added tracking for automation creation, updates, deletions, and trigger modifications, including success and failure events. - Implemented event tracking in the automation creation process, including chat approval and rejection scenarios. - Updated the instrumentation client to ensure correct typing for PostHog integration. - Refactored existing mutation atoms to include tracking calls for automation-related actions, improving analytics capabilities.
This commit is contained in:
parent
b1b51ada89
commit
92b1d7a9f7
4 changed files with 316 additions and 14 deletions
|
|
@ -7,6 +7,21 @@ import type {
|
||||||
TriggerUpdateRequest,
|
TriggerUpdateRequest,
|
||||||
} from "@/contracts/types/automation.types";
|
} from "@/contracts/types/automation.types";
|
||||||
import { automationsApiService } from "@/lib/apis/automations-api.service";
|
import { automationsApiService } from "@/lib/apis/automations-api.service";
|
||||||
|
import {
|
||||||
|
trackAutomationCreated,
|
||||||
|
trackAutomationCreateFailed,
|
||||||
|
trackAutomationDeleted,
|
||||||
|
trackAutomationDeleteFailed,
|
||||||
|
trackAutomationStatusChanged,
|
||||||
|
trackAutomationTriggerAdded,
|
||||||
|
trackAutomationTriggerAddFailed,
|
||||||
|
trackAutomationTriggerRemoved,
|
||||||
|
trackAutomationTriggerRemoveFailed,
|
||||||
|
trackAutomationTriggerUpdated,
|
||||||
|
trackAutomationTriggerUpdateFailed,
|
||||||
|
trackAutomationUpdated,
|
||||||
|
trackAutomationUpdateFailed,
|
||||||
|
} from "@/lib/posthog/events";
|
||||||
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
import { queryClient } from "@/lib/query-client/client";
|
import { queryClient } from "@/lib/query-client/client";
|
||||||
|
|
||||||
|
|
@ -33,13 +48,28 @@ export const createAutomationMutationAtom = atomWithMutation(() => ({
|
||||||
mutationFn: async (request: AutomationCreateRequest) => {
|
mutationFn: async (request: AutomationCreateRequest) => {
|
||||||
return automationsApiService.createAutomation(request);
|
return automationsApiService.createAutomation(request);
|
||||||
},
|
},
|
||||||
onSuccess: (_, variables) => {
|
onSuccess: (automation, variables) => {
|
||||||
invalidateList(variables.search_space_id);
|
invalidateList(variables.search_space_id);
|
||||||
toast.success("Automation created");
|
toast.success("Automation created");
|
||||||
|
trackAutomationCreated({
|
||||||
|
search_space_id: variables.search_space_id,
|
||||||
|
automation_id: automation.id,
|
||||||
|
task_count: variables.definition.plan.length,
|
||||||
|
trigger_type: variables.triggers?.[0]?.type ?? "none",
|
||||||
|
has_schedule: (variables.triggers?.length ?? 0) > 0,
|
||||||
|
agent_llm_id: variables.definition.models?.agent_llm_id,
|
||||||
|
image_generation_config_id: variables.definition.models?.image_generation_config_id,
|
||||||
|
vision_llm_config_id: variables.definition.models?.vision_llm_config_id,
|
||||||
|
tags_count: variables.definition.metadata?.tags?.length,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error, variables) => {
|
||||||
console.error("Error creating automation:", error);
|
console.error("Error creating automation:", error);
|
||||||
toast.error("Failed to create automation");
|
toast.error("Failed to create automation");
|
||||||
|
trackAutomationCreateFailed({
|
||||||
|
search_space_id: variables.search_space_id,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -52,10 +82,32 @@ export const updateAutomationMutationAtom = atomWithMutation(() => ({
|
||||||
invalidateDetail(vars.automationId);
|
invalidateDetail(vars.automationId);
|
||||||
invalidateList(automation.search_space_id);
|
invalidateList(automation.search_space_id);
|
||||||
toast.success("Automation updated");
|
toast.success("Automation updated");
|
||||||
|
// A status-only patch (pause/resume/archive) is a distinct action from a
|
||||||
|
// definition/name edit, so split it into its own event.
|
||||||
|
if (vars.patch.status && !vars.patch.definition) {
|
||||||
|
trackAutomationStatusChanged({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
search_space_id: automation.search_space_id,
|
||||||
|
next_status: vars.patch.status,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
trackAutomationUpdated({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
search_space_id: automation.search_space_id,
|
||||||
|
has_definition_change: !!vars.patch.definition,
|
||||||
|
has_name_change: vars.patch.name != null,
|
||||||
|
has_description_change: vars.patch.description !== undefined,
|
||||||
|
task_count: vars.patch.definition?.plan?.length,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error, vars) => {
|
||||||
console.error("Error updating automation:", error);
|
console.error("Error updating automation:", error);
|
||||||
toast.error("Failed to update automation");
|
toast.error("Failed to update automation");
|
||||||
|
trackAutomationUpdateFailed({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -69,10 +121,18 @@ export const deleteAutomationMutationAtom = atomWithMutation(() => ({
|
||||||
invalidateList(vars.searchSpaceId);
|
invalidateList(vars.searchSpaceId);
|
||||||
invalidateDetail(vars.automationId);
|
invalidateDetail(vars.automationId);
|
||||||
toast.success("Automation deleted");
|
toast.success("Automation deleted");
|
||||||
|
trackAutomationDeleted({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
search_space_id: vars.searchSpaceId,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error, vars) => {
|
||||||
console.error("Error deleting automation:", error);
|
console.error("Error deleting automation:", error);
|
||||||
toast.error("Failed to delete automation");
|
toast.error("Failed to delete automation");
|
||||||
|
trackAutomationDeleteFailed({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -81,13 +141,24 @@ export const addTriggerMutationAtom = atomWithMutation(() => ({
|
||||||
mutationFn: async (vars: { automationId: number; payload: TriggerCreateRequest }) => {
|
mutationFn: async (vars: { automationId: number; payload: TriggerCreateRequest }) => {
|
||||||
return automationsApiService.addTrigger(vars.automationId, vars.payload);
|
return automationsApiService.addTrigger(vars.automationId, vars.payload);
|
||||||
},
|
},
|
||||||
onSuccess: (_, vars) => {
|
onSuccess: (trigger, vars) => {
|
||||||
invalidateDetail(vars.automationId);
|
invalidateDetail(vars.automationId);
|
||||||
toast.success("Trigger added");
|
toast.success("Trigger added");
|
||||||
|
trackAutomationTriggerAdded({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
trigger_id: trigger.id,
|
||||||
|
trigger_type: trigger.type,
|
||||||
|
enabled: trigger.enabled,
|
||||||
|
has_cron: !!trigger.params?.cron,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error, vars) => {
|
||||||
console.error("Error adding trigger:", error);
|
console.error("Error adding trigger:", error);
|
||||||
toast.error("Failed to add trigger");
|
toast.error("Failed to add trigger");
|
||||||
|
trackAutomationTriggerAddFailed({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -103,10 +174,26 @@ export const updateTriggerMutationAtom = atomWithMutation(() => ({
|
||||||
onSuccess: (_, vars) => {
|
onSuccess: (_, vars) => {
|
||||||
invalidateDetail(vars.automationId);
|
invalidateDetail(vars.automationId);
|
||||||
toast.success("Trigger updated");
|
toast.success("Trigger updated");
|
||||||
|
const change: "enabled" | "params" | "other" = vars.patch.params
|
||||||
|
? "params"
|
||||||
|
: vars.patch.enabled !== undefined && vars.patch.enabled !== null
|
||||||
|
? "enabled"
|
||||||
|
: "other";
|
||||||
|
trackAutomationTriggerUpdated({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
trigger_id: vars.triggerId,
|
||||||
|
change,
|
||||||
|
enabled: vars.patch.enabled ?? undefined,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error, vars) => {
|
||||||
console.error("Error updating trigger:", error);
|
console.error("Error updating trigger:", error);
|
||||||
toast.error("Failed to update trigger");
|
toast.error("Failed to update trigger");
|
||||||
|
trackAutomationTriggerUpdateFailed({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
trigger_id: vars.triggerId,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -119,9 +206,18 @@ export const removeTriggerMutationAtom = atomWithMutation(() => ({
|
||||||
onSuccess: (vars) => {
|
onSuccess: (vars) => {
|
||||||
invalidateDetail(vars.automationId);
|
invalidateDetail(vars.automationId);
|
||||||
toast.success("Trigger removed");
|
toast.success("Trigger removed");
|
||||||
|
trackAutomationTriggerRemoved({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
trigger_id: vars.triggerId,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error, vars) => {
|
||||||
console.error("Error removing trigger:", error);
|
console.error("Error removing trigger:", error);
|
||||||
toast.error("Failed to remove trigger");
|
toast.error("Failed to remove trigger");
|
||||||
|
trackAutomationTriggerRemoveFailed({
|
||||||
|
automation_id: vars.automationId,
|
||||||
|
trigger_id: vars.triggerId,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import type { ToolCallMessagePartProps } from "@assistant-ui/react";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { AlertCircle, CornerDownLeftIcon, ExternalLink, Pencil, Workflow } from "lucide-react";
|
import { AlertCircle, CornerDownLeftIcon, ExternalLink, Pencil, Workflow } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
AutomationModelFields,
|
AutomationModelFields,
|
||||||
type AutomationModelSelection,
|
type AutomationModelSelection,
|
||||||
|
|
@ -17,6 +17,13 @@ import { automationCreateRequest } from "@/contracts/types/automation.types";
|
||||||
import type { HitlDecision, InterruptResult } from "@/features/chat-messages/hitl";
|
import type { HitlDecision, InterruptResult } from "@/features/chat-messages/hitl";
|
||||||
import { isInterruptResult, useHitlDecision, useHitlPhase } from "@/features/chat-messages/hitl";
|
import { isInterruptResult, useHitlDecision, useHitlPhase } from "@/features/chat-messages/hitl";
|
||||||
import { useAutomationEligibleModels } from "@/hooks/use-automation-eligible-models";
|
import { useAutomationEligibleModels } from "@/hooks/use-automation-eligible-models";
|
||||||
|
import {
|
||||||
|
trackAutomationChatApproved,
|
||||||
|
trackAutomationChatCreateFailed,
|
||||||
|
trackAutomationChatCreateSucceeded,
|
||||||
|
trackAutomationChatDraftEdited,
|
||||||
|
trackAutomationChatRejected,
|
||||||
|
} from "@/lib/posthog/events";
|
||||||
import { AutomationDraftPreview } from "./automation-draft-preview";
|
import { AutomationDraftPreview } from "./automation-draft-preview";
|
||||||
|
|
||||||
const editArgsSchema = automationCreateRequest.omit({ search_space_id: true });
|
const editArgsSchema = automationCreateRequest.omit({ search_space_id: true });
|
||||||
|
|
@ -145,6 +152,19 @@ function ApprovalCard({ args, interruptData, onDecision }: ApprovalCardProps) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const plan = Array.isArray(baseDefinition.plan) ? baseDefinition.plan : [];
|
||||||
|
const triggers = Array.isArray(baseArgs.triggers) ? baseArgs.triggers : [];
|
||||||
|
trackAutomationChatApproved({
|
||||||
|
search_space_id: searchSpaceId ? Number(searchSpaceId) : undefined,
|
||||||
|
edited: pendingEdits !== null,
|
||||||
|
task_count: plan.length,
|
||||||
|
trigger_type:
|
||||||
|
(triggers[0] as { type?: string } | undefined)?.type ??
|
||||||
|
(triggers.length ? undefined : "none"),
|
||||||
|
agent_llm_id: resolvedModels.agentLlmId,
|
||||||
|
image_generation_config_id: resolvedModels.imageConfigId,
|
||||||
|
vision_llm_config_id: resolvedModels.visionConfigId,
|
||||||
|
});
|
||||||
onDecision({
|
onDecision({
|
||||||
type: "edit",
|
type: "edit",
|
||||||
edited_action: {
|
edited_action: {
|
||||||
|
|
@ -163,13 +183,17 @@ function ApprovalCard({ args, interruptData, onDecision }: ApprovalCardProps) {
|
||||||
args,
|
args,
|
||||||
pendingEdits,
|
pendingEdits,
|
||||||
resolvedModels,
|
resolvedModels,
|
||||||
|
searchSpaceId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleReject = useCallback(() => {
|
const handleReject = useCallback(() => {
|
||||||
if (phase !== "pending" || !canReject || isEditing) return;
|
if (phase !== "pending" || !canReject || isEditing) return;
|
||||||
setRejected();
|
setRejected();
|
||||||
|
trackAutomationChatRejected({
|
||||||
|
search_space_id: searchSpaceId ? Number(searchSpaceId) : undefined,
|
||||||
|
});
|
||||||
onDecision({ type: "reject", message: "User rejected the automation draft." });
|
onDecision({ type: "reject", message: "User rejected the automation draft." });
|
||||||
}, [phase, canReject, isEditing, setRejected, onDecision]);
|
}, [phase, canReject, isEditing, setRejected, onDecision, searchSpaceId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEditing) return;
|
if (isEditing) return;
|
||||||
|
|
@ -242,6 +266,9 @@ function ApprovalCard({ args, interruptData, onDecision }: ApprovalCardProps) {
|
||||||
onSave={(parsed) => {
|
onSave={(parsed) => {
|
||||||
setPendingEdits(parsed);
|
setPendingEdits(parsed);
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
|
trackAutomationChatDraftEdited({
|
||||||
|
search_space_id: searchSpaceId ? Number(searchSpaceId) : undefined,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
onCancel={() => setIsEditing(false)}
|
onCancel={() => setIsEditing(false)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -356,6 +383,17 @@ function JsonEditor({ initialValue, onSave, onCancel }: JsonEditorProps) {
|
||||||
|
|
||||||
function SavedCard({ result }: { result: SavedResult }) {
|
function SavedCard({ result }: { result: SavedResult }) {
|
||||||
const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom);
|
const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom);
|
||||||
|
const tracked = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (tracked.current) return;
|
||||||
|
tracked.current = true;
|
||||||
|
trackAutomationChatCreateSucceeded({
|
||||||
|
automation_id: result.automation_id,
|
||||||
|
name: result.name,
|
||||||
|
search_space_id: searchSpaceId ? Number(searchSpaceId) : undefined,
|
||||||
|
});
|
||||||
|
}, [result.automation_id, result.name, searchSpaceId]);
|
||||||
|
|
||||||
const detailHref = searchSpaceId
|
const detailHref = searchSpaceId
|
||||||
? `/dashboard/${searchSpaceId}/automations/${result.automation_id}`
|
? `/dashboard/${searchSpaceId}/automations/${result.automation_id}`
|
||||||
: null;
|
: null;
|
||||||
|
|
@ -388,6 +426,18 @@ function SavedCard({ result }: { result: SavedResult }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function InvalidCard({ result }: { result: InvalidResult }) {
|
function InvalidCard({ result }: { result: InvalidResult }) {
|
||||||
|
const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom);
|
||||||
|
const tracked = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (tracked.current) return;
|
||||||
|
tracked.current = true;
|
||||||
|
trackAutomationChatCreateFailed({
|
||||||
|
reason: "invalid",
|
||||||
|
issue_count: result.issues.length,
|
||||||
|
search_space_id: searchSpaceId ? Number(searchSpaceId) : undefined,
|
||||||
|
});
|
||||||
|
}, [result.issues.length, searchSpaceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||||
<div className="px-5 pt-5 pb-4">
|
<div className="px-5 pt-5 pb-4">
|
||||||
|
|
@ -411,6 +461,18 @@ function InvalidCard({ result }: { result: InvalidResult }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ErrorCard({ result }: { result: ErrorResult }) {
|
function ErrorCard({ result }: { result: ErrorResult }) {
|
||||||
|
const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom);
|
||||||
|
const tracked = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (tracked.current) return;
|
||||||
|
tracked.current = true;
|
||||||
|
trackAutomationChatCreateFailed({
|
||||||
|
reason: "error",
|
||||||
|
message: result.message,
|
||||||
|
search_space_id: searchSpaceId ? Number(searchSpaceId) : undefined,
|
||||||
|
});
|
||||||
|
}, [result.message, searchSpaceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||||
<div className="px-5 pt-5 pb-4">
|
<div className="px-5 pt-5 pb-4">
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,12 @@ async function initPostHog() {
|
||||||
}
|
}
|
||||||
return event;
|
return event;
|
||||||
},
|
},
|
||||||
loaded: (ph) => {
|
loaded: () => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
window.posthog = ph;
|
// `loaded` hands back a `PostHogInterface`, but it's the same
|
||||||
|
// singleton as the default import (typed `PostHog`); use that to
|
||||||
|
// keep `window.posthog` correctly typed.
|
||||||
|
window.posthog = posthog;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
import posthog from "posthog-js";
|
||||||
import type { ChatErrorKind, ChatErrorSeverity, ChatFlow } from "@/lib/chat/chat-error-classifier";
|
import type { ChatErrorKind, ChatErrorSeverity, ChatFlow } from "@/lib/chat/chat-error-classifier";
|
||||||
import type { ConnectorTelemetryMeta } from "@/lib/connector-telemetry";
|
|
||||||
import { getConnectorTelemetryMeta } from "@/lib/connector-telemetry";
|
import { getConnectorTelemetryMeta } from "@/lib/connector-telemetry";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -19,6 +19,7 @@ import { getConnectorTelemetryMeta } from "@/lib/connector-telemetry";
|
||||||
* - connector: External connector events (all lifecycle stages)
|
* - connector: External connector events (all lifecycle stages)
|
||||||
* - contact: Contact form events
|
* - contact: Contact form events
|
||||||
* - settings: Settings changes
|
* - settings: Settings changes
|
||||||
|
* - automation: Automation lifecycle (create/update/delete/trigger/chat)
|
||||||
* - marketing: Marketing/referral tracking
|
* - marketing: Marketing/referral tracking
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ function safeCapture(event: string, properties?: Record<string, unknown>) {
|
||||||
/**
|
/**
|
||||||
* Drop undefined values so PostHog doesn't log `"foo": undefined` noise.
|
* Drop undefined values so PostHog doesn't log `"foo": undefined` noise.
|
||||||
*/
|
*/
|
||||||
function compact<T extends Record<string, unknown>>(obj: T): Record<string, unknown> {
|
function compact<T extends object>(obj: T): Record<string, unknown> {
|
||||||
const out: Record<string, unknown> = {};
|
const out: Record<string, unknown> = {};
|
||||||
for (const [k, v] of Object.entries(obj)) {
|
for (const [k, v] of Object.entries(obj)) {
|
||||||
if (v !== undefined) out[k] = v;
|
if (v !== undefined) out[k] = v;
|
||||||
|
|
@ -598,6 +599,146 @@ export function trackReferralLanding(refCode: string, landingUrl: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// AUTOMATION EVENTS
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
interface AutomationCreatedProps {
|
||||||
|
search_space_id: number;
|
||||||
|
automation_id: number;
|
||||||
|
task_count?: number;
|
||||||
|
trigger_type?: string;
|
||||||
|
has_schedule?: boolean;
|
||||||
|
agent_llm_id?: number;
|
||||||
|
image_generation_config_id?: number;
|
||||||
|
vision_llm_config_id?: number;
|
||||||
|
tags_count?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationCreated(props: AutomationCreatedProps) {
|
||||||
|
safeCapture("automation_created", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationCreateFailed(props: { search_space_id?: number; error?: string }) {
|
||||||
|
safeCapture("automation_create_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationUpdated(props: {
|
||||||
|
automation_id: number;
|
||||||
|
search_space_id?: number;
|
||||||
|
has_definition_change?: boolean;
|
||||||
|
has_name_change?: boolean;
|
||||||
|
has_description_change?: boolean;
|
||||||
|
task_count?: number;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_updated", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationStatusChanged(props: {
|
||||||
|
automation_id: number;
|
||||||
|
search_space_id?: number;
|
||||||
|
next_status: string;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_status_changed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationUpdateFailed(props: { automation_id: number; error?: string }) {
|
||||||
|
safeCapture("automation_update_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationDeleted(props: { automation_id: number; search_space_id?: number }) {
|
||||||
|
safeCapture("automation_deleted", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationDeleteFailed(props: { automation_id: number; error?: string }) {
|
||||||
|
safeCapture("automation_delete_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationTriggerAdded(props: {
|
||||||
|
automation_id: number;
|
||||||
|
trigger_id?: number;
|
||||||
|
trigger_type?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
has_cron?: boolean;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_trigger_added", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationTriggerAddFailed(props: { automation_id: number; error?: string }) {
|
||||||
|
safeCapture("automation_trigger_add_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationTriggerUpdated(props: {
|
||||||
|
automation_id: number;
|
||||||
|
trigger_id: number;
|
||||||
|
change?: "enabled" | "params" | "other";
|
||||||
|
enabled?: boolean;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_trigger_updated", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationTriggerUpdateFailed(props: {
|
||||||
|
automation_id: number;
|
||||||
|
trigger_id: number;
|
||||||
|
error?: string;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_trigger_update_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationTriggerRemoved(props: {
|
||||||
|
automation_id: number;
|
||||||
|
trigger_id: number;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_trigger_removed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationTriggerRemoveFailed(props: {
|
||||||
|
automation_id: number;
|
||||||
|
trigger_id: number;
|
||||||
|
error?: string;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_trigger_remove_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AutomationChatDecisionProps {
|
||||||
|
search_space_id?: number;
|
||||||
|
edited?: boolean;
|
||||||
|
task_count?: number;
|
||||||
|
trigger_type?: string;
|
||||||
|
agent_llm_id?: number;
|
||||||
|
image_generation_config_id?: number;
|
||||||
|
vision_llm_config_id?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationChatApproved(props: AutomationChatDecisionProps) {
|
||||||
|
safeCapture("automation_chat_approved", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationChatRejected(props: { search_space_id?: number }) {
|
||||||
|
safeCapture("automation_chat_rejected", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationChatDraftEdited(props: { search_space_id?: number }) {
|
||||||
|
safeCapture("automation_chat_draft_edited", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationChatCreateSucceeded(props: {
|
||||||
|
automation_id: number;
|
||||||
|
name?: string;
|
||||||
|
search_space_id?: number;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_chat_create_succeeded", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackAutomationChatCreateFailed(props: {
|
||||||
|
reason: "invalid" | "error";
|
||||||
|
search_space_id?: number;
|
||||||
|
issue_count?: number;
|
||||||
|
message?: string;
|
||||||
|
}) {
|
||||||
|
safeCapture("automation_chat_create_failed", compact(props));
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// USER IDENTIFICATION
|
// USER IDENTIFICATION
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue