@@ -32,9 +32,12 @@ import {
3232 FlowRunStatus ,
3333 FlowVersion ,
3434 isNil ,
35+ RiskLevel ,
3536 TriggerType ,
3637} from '@openops/shared' ;
3738
39+ import { getActionMetadata } from '@/app/features/flows/components/execute-risky-flow-dialog/utils' ;
40+ import { ShieldHalf } from 'lucide-react' ;
3841import { CanvasContextMenu } from '../context-menu/canvas-context-menu' ;
3942import { CollapsibleButton } from './collapsible-button' ;
4043import { StackedNodeLayers } from './stacked-node-layer' ;
@@ -86,6 +89,11 @@ const WorkflowStepNode = React.memo(
8689 step : data . step ! ,
8790 } ) ;
8891
92+ const { metadata : actionsMetadata } = blocksHooks . useAllStepsMetadata ( {
93+ searchQuery : '' ,
94+ type : 'action' ,
95+ } ) ;
96+
8997 const stepIndex = useMemo ( ( ) => {
9098 const steps = flowHelper . getAllSteps ( flowVersion . trigger ) ;
9199 return steps . findIndex ( ( step ) => step . name === data . step ! . name ) + 1 ;
@@ -122,6 +130,27 @@ const WorkflowStepNode = React.memo(
122130 return getStepStatus ( data . step ?. name , run , loopIndexes , flowVersion ) ;
123131 } , [ data . step ?. name , run , loopIndexes , flowVersion ] ) ;
124132
133+ const isRiskyStep = useMemo ( ( ) => {
134+ const actionName = data . step ?. settings . actionName ;
135+ const blockName = data . step ?. settings . blockName ;
136+
137+ if ( ! actionsMetadata || ! actionName || ! blockName ) {
138+ return false ;
139+ }
140+
141+ const actionMetadata = getActionMetadata (
142+ actionsMetadata ,
143+ data . step ?. settings . blockName ,
144+ data . step ?. settings . actionName ,
145+ ) ;
146+
147+ return actionMetadata ?. riskLevel === RiskLevel . HIGH ;
148+ } , [
149+ actionsMetadata ,
150+ data . step ?. settings . actionName ,
151+ data . step ?. settings . blockName ,
152+ ] ) ;
153+
125154 const showRunningIcon =
126155 isNil ( stepOutputStatus ) && run ?. status === FlowRunStatus . RUNNING ;
127156 const statusInfo = isNil ( stepOutputStatus )
@@ -247,15 +276,49 @@ const WorkflowStepNode = React.memo(
247276 </ div >
248277 </ div >
249278
250- { ! readonly && (
251- < CanvasContextMenu
252- data = { data }
253- isAction = { isAction }
254- openStepActionsMenu = { openStepActionsMenu }
255- setOpenStepActionsMenu = { setOpenStepActionsMenu }
256- setOpenBlockSelector = { setOpenBlockSelector }
257- />
258- ) }
279+ < div className = "flex items-center gap-0.5" >
280+ < div className = "flex items-center gap-[7px]" >
281+ { ! data . step ?. valid && (
282+ < Tooltip >
283+ < TooltipTrigger asChild >
284+ < InvalidStepIcon
285+ size = { 16 }
286+ viewBox = "0 0 16 16"
287+ className = "stroke-0 animate-fade"
288+ > </ InvalidStepIcon >
289+ </ TooltipTrigger >
290+ < TooltipContent side = "bottom" >
291+ { t ( 'Incomplete settings' ) }
292+ </ TooltipContent >
293+ </ Tooltip >
294+ ) }
295+
296+ { isRiskyStep && (
297+ < Tooltip >
298+ < TooltipTrigger asChild >
299+ < div className = "size-4 flex items-center justify-center rounded-full bg-destructive-100" >
300+ < ShieldHalf className = "size-[10px] text-destructive-300" > </ ShieldHalf >
301+ </ div >
302+ </ TooltipTrigger >
303+ < TooltipContent side = "bottom" >
304+ { t (
305+ 'This step may make changes to your environment' ,
306+ ) }
307+ </ TooltipContent >
308+ </ Tooltip >
309+ ) }
310+ </ div >
311+
312+ { ! readonly && (
313+ < CanvasContextMenu
314+ data = { data }
315+ isAction = { isAction }
316+ openStepActionsMenu = { openStepActionsMenu }
317+ setOpenStepActionsMenu = { setOpenStepActionsMenu }
318+ setOpenBlockSelector = { setOpenBlockSelector }
319+ />
320+ ) }
321+ </ div >
259322 </ div >
260323
261324 < div className = "flex justify-between gap-[6px] w-full items-center" >
@@ -276,22 +339,6 @@ const WorkflowStepNode = React.memo(
276339 { showRunningIcon && (
277340 < LoadingSpinner className = "w-4 h-4 text-primary" > </ LoadingSpinner >
278341 ) }
279- { ! data . step ?. valid && (
280- < Tooltip >
281- < TooltipTrigger asChild >
282- < div className = "mr-2" >
283- < InvalidStepIcon
284- size = { 16 }
285- viewBox = "0 0 16 16"
286- className = "stroke-0 animate-fade"
287- > </ InvalidStepIcon >
288- </ div >
289- </ TooltipTrigger >
290- < TooltipContent side = "bottom" >
291- { t ( 'Incomplete settings' ) }
292- </ TooltipContent >
293- </ Tooltip >
294- ) }
295342 </ div >
296343 </ div >
297344 </ div >
0 commit comments