33import { useCallback , useMemo , useReducer , useRef , useState } from 'react'
44import { createLogger } from '@sim/logger'
55import { useParams , useRouter } from 'next/navigation'
6+ import { usePostHog } from 'posthog-js/react'
67import {
78 Button ,
89 Modal ,
@@ -15,6 +16,7 @@ import {
1516} from '@/components/emcn'
1617import { Download , Pencil , Table as TableIcon , Trash , Upload } from '@/components/emcn/icons'
1718import type { RunLimit , RunMode } from '@/lib/api/contracts/tables'
19+ import { captureEvent } from '@/lib/posthog/client'
1820import type { ColumnDefinition , Filter , TableRow as TableRowType , WorkflowGroup } from '@/lib/table'
1921import {
2022 type ColumnOption ,
@@ -123,6 +125,10 @@ export function Table({
123125 const workspaceId = propWorkspaceId || ( params . workspaceId as string )
124126 const tableId = propTableId || ( params . tableId as string )
125127
128+ const posthog = usePostHog ( )
129+ const posthogRef = useRef ( posthog )
130+ posthogRef . current = posthog
131+
126132 useTableEventStream ( { tableId, workspaceId } )
127133
128134 const [ slideout , dispatch ] = useReducer ( slideoutReducer , { kind : 'none' } )
@@ -225,24 +231,40 @@ export function Table({
225231 // gutter, action-bar Play/Refresh, right-click context menu) reduces to a
226232 // (groupIds, rowIds?, runMode) triple. Empty groupIds = no-op.
227233 const runScope = useCallback (
228- ( args : { groupIds : string [ ] ; rowIds ?: string [ ] ; runMode : RunMode ; limit ?: RunLimit } ) => {
229- if ( args . groupIds . length === 0 ) return
230- if ( args . rowIds && args . rowIds . length === 0 ) return
231- runColumnMutate ( args )
234+ ( args : {
235+ groupIds : string [ ]
236+ rowIds ?: string [ ]
237+ runMode : RunMode
238+ limit ?: RunLimit
239+ source : 'row' | 'rows' | 'column'
240+ } ) => {
241+ const { source, ...mutateArgs } = args
242+ if ( mutateArgs . groupIds . length === 0 ) return
243+ if ( mutateArgs . rowIds && mutateArgs . rowIds . length === 0 ) return
244+ runColumnMutate ( mutateArgs )
245+ captureEvent ( posthogRef . current , 'table_workflow_run' , {
246+ table_id : tableId ,
247+ workspace_id : workspaceId ,
248+ source,
249+ run_mode : mutateArgs . runMode ,
250+ group_count : mutateArgs . groupIds . length ,
251+ row_count : mutateArgs . rowIds ?. length ?? null ,
252+ has_limit : mutateArgs . limit != null ,
253+ } )
232254 } ,
233- [ runColumnMutate ]
255+ [ runColumnMutate , tableId , workspaceId ]
234256 )
235257
236258 const onRunColumn = useCallback (
237259 ( groupId : string , runMode : RunMode , rowIds ?: string [ ] , limit ?: RunLimit ) => {
238- runScope ( { groupIds : [ groupId ] , rowIds, runMode, limit } )
260+ runScope ( { groupIds : [ groupId ] , rowIds, runMode, limit, source : 'column' } )
239261 } ,
240262 [ runScope ]
241263 )
242264
243265 const onRunRows = useCallback (
244266 ( rowIds : string [ ] , runMode : RunMode ) => {
245- runScope ( { groupIds : tableWorkflowGroups . map ( ( g ) => g . id ) , rowIds, runMode } )
267+ runScope ( { groupIds : tableWorkflowGroups . map ( ( g ) => g . id ) , rowIds, runMode, source : 'rows' } )
246268 } ,
247269 [ runScope , tableWorkflowGroups ]
248270 )
@@ -253,6 +275,7 @@ export function Table({
253275 groupIds : tableWorkflowGroups . map ( ( g ) => g . id ) ,
254276 rowIds : [ rowId ] ,
255277 runMode : 'incomplete' ,
278+ source : 'row' ,
256279 } )
257280 } ,
258281 [ runScope , tableWorkflowGroups ]
@@ -263,21 +286,39 @@ export function Table({
263286 const onStopRow = useCallback (
264287 ( rowId : string ) => {
265288 cancelRunsMutate ( { scope : 'row' , rowId } )
289+ captureEvent ( posthogRef . current , 'table_workflow_stopped' , {
290+ table_id : tableId ,
291+ workspace_id : workspaceId ,
292+ scope : 'row' ,
293+ row_count : 1 ,
294+ } )
266295 } ,
267- [ cancelRunsMutate ]
296+ [ cancelRunsMutate , tableId , workspaceId ]
268297 )
269298
270299 const onStopRows = ( rowIds : string [ ] ) => {
271300 if ( rowIds . length === 0 ) return
272301 for ( const rowId of rowIds ) {
273302 cancelRunsMutate ( { scope : 'row' , rowId } )
274303 }
304+ captureEvent ( posthogRef . current , 'table_workflow_stopped' , {
305+ table_id : tableId ,
306+ workspace_id : workspaceId ,
307+ scope : 'rows' ,
308+ row_count : rowIds . length ,
309+ } )
275310 }
276311
277312 // useCallback because <RunStatusControl> is memo-wrapped.
278313 const onStopAll = useCallback ( ( ) => {
279314 cancelRunsMutate ( { scope : 'all' } )
280- } , [ cancelRunsMutate ] )
315+ captureEvent ( posthogRef . current , 'table_workflow_stopped' , {
316+ table_id : tableId ,
317+ workspace_id : workspaceId ,
318+ scope : 'all' ,
319+ row_count : null ,
320+ } )
321+ } , [ cancelRunsMutate , tableId , workspaceId ] )
281322
282323 const onSelectionChange = ( next : SelectionSnapshot ) => {
283324 setSelection ( next )
0 commit comments