diff --git a/packages/sanity/src/tasks/__telemetry__/tasks.telemetry.ts b/packages/sanity/src/tasks/__telemetry__/tasks.telemetry.ts
new file mode 100644
index 00000000000..1ddaf5d5280
--- /dev/null
+++ b/packages/sanity/src/tasks/__telemetry__/tasks.telemetry.ts
@@ -0,0 +1,46 @@
+import {defineEvent} from '@sanity/telemetry'
+
+// Task is created.
+export const TaskCreated = defineEvent({
+ name: 'Task Created',
+ version: 1,
+ description: 'A task is created',
+})
+
+// Task status changed. %from% - %to%
+export const TaskStatusChanged = defineEvent<{
+ from: string
+ to: string
+}>({
+ name: 'Task Status Changed',
+ version: 1,
+ description: 'Task status changed',
+})
+
+// A task is duplicated
+export const TaskDuplicated = defineEvent({
+ name: 'Task Duplicated',
+ version: 1,
+ description: 'A task is duplicated',
+})
+
+// A task is removed
+export const TaskRemoved = defineEvent({
+ name: 'Task Removed',
+ version: 1,
+ description: 'A task is removed',
+})
+
+// The link to a task is copied
+export const TaskLinkCopied = defineEvent({
+ name: 'Task Link Copied',
+ version: 1,
+ description: 'The link to a task is copied',
+})
+
+// User visited the studio through a link with a task
+export const TaskLinkOpened = defineEvent({
+ name: 'Task Link Opened',
+ version: 1,
+ description: 'User visited the studio through a link with a task',
+})
diff --git a/packages/sanity/src/tasks/src/tasks/components/form/fields/StatusSelector.tsx b/packages/sanity/src/tasks/src/tasks/components/form/fields/StatusSelector.tsx
index 41ccd1db6cf..ac9e0129411 100644
--- a/packages/sanity/src/tasks/src/tasks/components/form/fields/StatusSelector.tsx
+++ b/packages/sanity/src/tasks/src/tasks/components/form/fields/StatusSelector.tsx
@@ -1,6 +1,7 @@
import {CheckmarkIcon, CircleIcon} from '@sanity/icons'
+import {useTelemetry} from '@sanity/telemetry/react'
import {Menu} from '@sanity/ui'
-import {type ForwardedRef, forwardRef} from 'react'
+import {type ForwardedRef, forwardRef, useCallback} from 'react'
import {
type FormPatch,
isString,
@@ -12,6 +13,7 @@ import {
} from 'sanity'
import {Button, MenuButton, MenuItem} from '../../../../../../ui-components'
+import {TaskStatusChanged} from '../../../../../__telemetry__/tasks.telemetry'
import {tasksLocaleNamespace} from '../../../../../i18n'
import {TASK_STATUS} from '../../../constants/TaskStatus'
@@ -45,6 +47,16 @@ interface StatusSelectorProps {
export function StatusSelector(props: StatusSelectorProps) {
const {value, onChange, options, path} = props
+ const telemetry = useTelemetry()
+
+ const handleStatusChange = useCallback(
+ (next?: string) => {
+ onChange(set(next, path))
+ telemetry.log(TaskStatusChanged, {from: value, to: next})
+ },
+ [onChange, path, telemetry, value],
+ )
+
return (
}
@@ -62,7 +74,7 @@ export function StatusSelector(props: StatusSelectorProps) {
pressed={isSelected}
iconRight={isSelected && }
// eslint-disable-next-line react/jsx-no-bind
- onClick={() => onChange(set(option.value, path))}
+ onClick={() => handleStatusChange(option.value)}
/>
)
})}
diff --git a/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormCreate.tsx b/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormCreate.tsx
index 2197582c540..fb2d69409b9 100644
--- a/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormCreate.tsx
+++ b/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormCreate.tsx
@@ -1,9 +1,11 @@
import {TrashIcon} from '@sanity/icons'
+import {useTelemetry} from '@sanity/telemetry/react'
import {Box, Flex, Switch, Text, useToast} from '@sanity/ui'
import {useCallback, useState} from 'react'
import {type ObjectInputProps, set, useTranslation} from 'sanity'
import {Button} from '../../../../../../ui-components'
+import {TaskCreated} from '../../../../../__telemetry__/tasks.telemetry'
import {tasksLocaleNamespace} from '../../../../../i18n'
import {useTasksNavigation} from '../../../context'
import {useRemoveTask} from '../../../hooks/useRemoveTask'
@@ -26,16 +28,18 @@ const getTaskSubscribers = (task: TaskDocument): string[] => {
return subscribers
}
export function FormCreate(props: ObjectInputProps) {
- const [createMore, setCreateMore] = useState(false)
+ const {onChange} = props
const {
setViewMode,
setActiveTab,
state: {viewMode},
} = useTasksNavigation()
-
const toast = useToast()
+ const telemetry = useTelemetry()
+
+ const [createMore, setCreateMore] = useState(false)
const handleCreateMore = useCallback(() => setCreateMore((p) => !p), [])
- const {onChange} = props
+
const value = props.value as TaskDocument
const onRemove = useCallback(() => {
setViewMode({type: 'list'})
@@ -62,12 +66,14 @@ export function FormCreate(props: ObjectInputProps) {
setActiveTab('subscribed')
}
+ telemetry.log(TaskCreated)
+
toast.push({
closable: true,
status: 'success',
title: t('form.status.success'),
})
- }, [setViewMode, setActiveTab, onChange, createMore, toast, value, t])
+ }, [value, onChange, createMore, telemetry, toast, t, setViewMode, setActiveTab])
return (
<>
diff --git a/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormEdit.tsx b/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormEdit.tsx
index 2aa20b4c3ac..366e303be76 100644
--- a/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormEdit.tsx
+++ b/packages/sanity/src/tasks/src/tasks/components/form/tasksFormBuilder/FormEdit.tsx
@@ -1,4 +1,5 @@
import {CopyIcon, LinkIcon, TrashIcon} from '@sanity/icons'
+import {useTelemetry} from '@sanity/telemetry/react'
import {Box, Card, Flex, Menu, MenuDivider, Stack} from '@sanity/ui'
// eslint-disable-next-line camelcase
import {getTheme_v2} from '@sanity/ui/theme'
@@ -19,6 +20,7 @@ import {css, styled} from 'styled-components'
import {CommentsProvider} from '../../../../../../structure/comments'
import {MenuButton, MenuItem, TooltipDelayGroupProvider} from '../../../../../../ui-components'
+import {TaskDuplicated, TaskRemoved} from '../../../../../__telemetry__/tasks.telemetry'
import {tasksLocaleNamespace} from '../../../../../i18n'
import {useTasksEnabled, useTasksNavigation} from '../../../context'
import {useActivityLog} from '../../../hooks/useActivityLog'
@@ -44,14 +46,18 @@ const FirstRow = styled(Flex)((props) => {
function FormActionsMenu({id, value}: {id: string; value: TaskDocument}) {
const {setViewMode, handleCopyLinkToTask} = useTasksNavigation()
const {mode} = useTasksEnabled()
+ const telemetry = useTelemetry()
+
const onTaskRemoved = useCallback(() => {
setViewMode({type: 'list'})
- }, [setViewMode])
+ telemetry.log(TaskRemoved)
+ }, [setViewMode, telemetry])
const removeTask = useRemoveTask({id, onRemoved: onTaskRemoved})
const duplicateTask = useCallback(() => {
setViewMode({type: 'duplicate', duplicateTaskValues: value})
- }, [setViewMode, value])
+ telemetry.log(TaskDuplicated)
+ }, [setViewMode, telemetry, value])
const {t} = useTranslation(tasksLocaleNamespace)
diff --git a/packages/sanity/src/tasks/src/tasks/context/navigation/TasksNavigationProvider.tsx b/packages/sanity/src/tasks/src/tasks/context/navigation/TasksNavigationProvider.tsx
index 3dde28c2cf8..1a43f76b29c 100644
--- a/packages/sanity/src/tasks/src/tasks/context/navigation/TasksNavigationProvider.tsx
+++ b/packages/sanity/src/tasks/src/tasks/context/navigation/TasksNavigationProvider.tsx
@@ -1,8 +1,10 @@
+import {useTelemetry} from '@sanity/telemetry/react'
import {useToast} from '@sanity/ui'
import {uuid} from '@sanity/uuid'
import {type ReactNode, useCallback, useEffect, useReducer} from 'react'
import {useRouter} from 'sanity/router'
+import {TaskLinkCopied, TaskLinkOpened} from '../../../../__telemetry__/tasks.telemetry'
import {TasksNavigationContext} from './TasksNavigationContext'
import {type Action, type SidebarTabsIds, type State, type ViewModeOptions} from './types'
@@ -73,6 +75,7 @@ export const TasksNavigationProvider = ({children}: {children: ReactNode}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const router = useRouter()
const toast = useToast()
+ const telemetry = useTelemetry()
const setViewMode = useCallback((viewMode: ViewModeOptions) => {
switch (viewMode.type) {
@@ -126,6 +129,7 @@ export const TasksNavigationProvider = ({children}: {children: ReactNode}) => {
status: 'info',
title: 'Copied link to clipboard',
})
+ telemetry.log(TaskLinkCopied)
})
.catch(() => {
toast.push({
@@ -134,7 +138,7 @@ export const TasksNavigationProvider = ({children}: {children: ReactNode}) => {
title: 'Failed to copy link to clipboard',
})
})
- }, [state.selectedTask, state.viewMode, toast])
+ }, [state.selectedTask, state.viewMode, telemetry, toast])
// This is casted to a string to make it stable across renders so it doesn't trigger multiple times the effect.
const searchParamsAsString = new URLSearchParams(router.state._searchParams).toString()
@@ -152,9 +156,10 @@ export const TasksNavigationProvider = ({children}: {children: ReactNode}) => {
const selectedTask = searchParams.get('selectedTask')
if (viewMode === 'edit' && selectedTask) {
dispatch({type: 'EDIT_TASK', payload: {id: selectedTask}})
+ telemetry.log(TaskLinkOpened)
}
}
- }, [searchParamsAsString])
+ }, [searchParamsAsString, telemetry])
return (