@@ -799,6 +799,7 @@ func (c *Client) EventsHandler(writer http.ResponseWriter, r *http.Request) {
799799 c .homeViewHandlerMu .RUnlock ()
800800
801801 if handler != nil {
802+ //nolint:contextcheck // Use detached context for async event processing - prevents webhook events from being lost during shutdown
802803 go func (teamID , userID string ) {
803804 homeCtx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
804805 defer cancel ()
@@ -858,7 +859,8 @@ func (c *Client) InteractionsHandler(writer http.ResponseWriter, r *http.Request
858859 switch interaction .Type {
859860 case slack .InteractionTypeBlockActions :
860861 // Handle block actions (buttons, selects, etc.).
861- slog .Debug ("received block action" , "interaction" , interaction )
862+ //nolint:contextcheck // handleBlockAction spawns async goroutines with detached contexts - this is intentional
863+ c .handleBlockAction (& interaction )
862864 case slack .InteractionTypeViewSubmission :
863865 // Handle modal submissions.
864866 slog .Debug ("received view submission" , "interaction" , interaction )
@@ -870,6 +872,51 @@ func (c *Client) InteractionsHandler(writer http.ResponseWriter, r *http.Request
870872 writer .WriteHeader (http .StatusOK )
871873}
872874
875+ // handleBlockAction handles block action interactions (button clicks, etc.).
876+ func (c * Client ) handleBlockAction (interaction * slack.InteractionCallback ) {
877+ // Process each action in the callback
878+ for _ , action := range interaction .ActionCallback .BlockActions {
879+ slog .Debug ("processing block action" ,
880+ "action_id" , action .ActionID ,
881+ "user" , interaction .User .ID ,
882+ "team" , interaction .Team .ID )
883+
884+ switch action .ActionID {
885+ case "refresh_dashboard" :
886+ // Trigger home view refresh
887+ c .homeViewHandlerMu .RLock ()
888+ handler := c .homeViewHandler
889+ c .homeViewHandlerMu .RUnlock ()
890+
891+ if handler != nil {
892+ // Refresh asynchronously to avoid blocking the response
893+ //nolint:contextcheck // Use detached context for async button refresh - ensures operation completes even if parent context is cancelled
894+ go func (teamID , userID string ) {
895+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
896+ defer cancel ()
897+
898+ slog .Info ("refreshing dashboard via button click" ,
899+ "team_id" , teamID ,
900+ "user" , userID )
901+
902+ if err := handler (ctx , teamID , userID ); err != nil {
903+ slog .Error ("failed to refresh dashboard" ,
904+ "team_id" , teamID ,
905+ "user" , userID ,
906+ "error" , err )
907+ }
908+ }(interaction .Team .ID , interaction .User .ID )
909+ } else {
910+ slog .Warn ("refresh requested but no home view handler registered" ,
911+ "user" , interaction .User .ID )
912+ }
913+
914+ default :
915+ slog .Debug ("unhandled action_id" , "action_id" , action .ActionID )
916+ }
917+ }
918+ }
919+
873920// SlashCommandHandler handles Slack slash commands.
874921func (c * Client ) SlashCommandHandler (writer http.ResponseWriter , r * http.Request ) {
875922 // Verify the request signature.
0 commit comments