@@ -16,10 +16,8 @@ import { AWSTreeNodeBase } from '../../shared/treeview/nodes/awsTreeNodeBase'
1616import  {  PlaceholderNode  }  from  '../../shared/treeview/nodes/placeholderNode' 
1717import  {  makeChildrenNodes  }  from  '../../shared/treeview/utils' 
1818import  {  toArrayAsync ,  toMap ,  updateInPlace  }  from  '../../shared/utilities/collectionUtils' 
19- import  {  listStateMachines  }  from  '../../stepFunctions/utils' 
20- import  {  getIcon  }  from  '../../shared/icons' 
21- 
22- export  const  contextValueStateMachine  =  'awsStateMachineNode' 
19+ import  {  listStateMachines ,  listExecutions  }  from  '../../stepFunctions/utils' 
20+ import  {  getIcon ,  IconPath  }  from  '../../shared/icons' 
2321
2422const  sfnNodeMap  =  new  Map < string ,  StepFunctionsNode > ( ) 
2523
@@ -74,20 +72,70 @@ export class StepFunctionsNode extends AWSTreeNodeBase {
7472            this . stateMachineNodes , 
7573            functions . keys ( ) , 
7674            ( key )  =>  this . stateMachineNodes . get ( key ) ! . update ( functions . get ( key ) ! ) , 
77-             ( key )  =>  makeStateMachineNode ( this ,  this . regionCode ,  functions . get ( key ) ! ) 
75+             ( key )  =>  new   StateMachineNode ( this ,  this . regionCode ,  functions . get ( key ) ! ,   this . client ) 
7876        ) 
7977    } 
8078} 
8179
80+ /** 
81+  * Represents a Step Functions state machine in the Explorer view. This node 
82+  * appears immediately underneath the "Step Functions" node. A StateMachineNode 
83+  * will contain children of type StateMachineExecutionNode, representing 
84+  * the most recent executions of that state machine. 
85+  */ 
8286export  class  StateMachineNode  extends  AWSTreeNodeBase  implements  AWSResourceNode  { 
87+     public  static  readonly  contextValue  =  'awsStateMachineNode' 
88+     public  static  readonly  maxExecutionsToShow  =  10 
89+ 
90+     private  readonly  stateMachineExecutionNodes : Map < string ,  StateMachineExecutionNode > 
91+ 
8392    public  constructor ( 
8493        public  readonly  parent : AWSTreeNodeBase , 
8594        public  override  readonly  regionCode : string , 
86-         public  details : StepFunctions . StateMachineListItem 
95+         public  details : StepFunctions . StateMachineListItem , 
96+         private  readonly  client : StepFunctionsClient 
8797    )  { 
88-         super ( '' ) 
98+         super ( '' ,  vscode . TreeItemCollapsibleState . Collapsed ) 
99+         this . stateMachineExecutionNodes  =  new  Map < string ,  StateMachineExecutionNode > ( ) 
89100        this . update ( details ) 
90101        this . iconPath  =  getIcon ( 'aws-stepfunctions-preview' ) 
102+         this . contextValue  =  StateMachineNode . contextValue 
103+     } 
104+ 
105+     public  override  async  getChildren ( ) : Promise < AWSTreeNodeBase [ ] >  { 
106+         return  await  makeChildrenNodes ( { 
107+             getChildNodes : async  ( )  =>  { 
108+                 await  this . updateChildren ( ) 
109+                 return  [ ...this . stateMachineExecutionNodes . values ( ) ] 
110+             } , 
111+             getNoChildrenPlaceholderNode : async  ( )  => 
112+                 new  PlaceholderNode ( 
113+                     this , 
114+                     localize ( 'AWS.explorerNode.stepfunctions.noStateMachineExecution' ,  '[No Executions found]' ) 
115+                 ) , 
116+             /* 
117+              * Note: although Step Functions returns the executions in the correct order, this sorting 
118+              * is still needed to ensure newly added nodes (via updateChildren()) appear in the correct place. 
119+              */ 
120+             sort : ( nodeA ,  nodeB )  =>  { 
121+                 const  dateA  =  nodeA . details . startDate  as  Date  // startDate will never be undefined. 
122+                 const  dateB  =  nodeB . details . startDate  as  Date 
123+                 return  dateB . getTime ( )  -  dateA . getTime ( ) 
124+             } , 
125+         } ) 
126+     } 
127+ 
128+     public  async  updateChildren ( ) : Promise < void >  { 
129+         const  executions : Map < string ,  StepFunctions . ExecutionListItem >  =  toMap ( 
130+             await  toArrayAsync ( listExecutions ( this . client ,  this . arn ,  StateMachineNode . maxExecutionsToShow ) ) , 
131+             ( details )  =>  details . name 
132+         ) 
133+         updateInPlace ( 
134+             this . stateMachineExecutionNodes , 
135+             executions . keys ( ) , 
136+             ( key )  =>  this . stateMachineExecutionNodes . get ( key ) ! . update ( executions . get ( key ) ! ) , 
137+             ( key )  =>  new  StateMachineExecutionNode ( this ,  this . regionCode ,  executions . get ( key ) ! ) 
138+         ) 
91139    } 
92140
93141    public  update ( details : StepFunctions . StateMachineListItem ) : void { 
@@ -113,13 +161,61 @@ export class StateMachineNode extends AWSTreeNodeBase implements AWSResourceNode
113161    } 
114162} 
115163
116- function  makeStateMachineNode ( 
117-     parent : AWSTreeNodeBase , 
118-     regionCode : string , 
119-     details : StepFunctions . StateMachineListItem 
120- ) : StateMachineNode  { 
121-     const  node  =  new  StateMachineNode ( parent ,  regionCode ,  details ) 
122-     node . contextValue  =  contextValueStateMachine 
164+ /** 
165+  * Represents a single execution of a Step Functions state machine in the Explorer 
166+  * view. This node appears immediately underneath the corresponding StateMachineNode. 
167+  */ 
168+ export  class  StateMachineExecutionNode  extends  AWSTreeNodeBase  implements  AWSResourceNode  { 
169+     public  static  contextValue  =  'awsStateMachineExecutionNode' 
170+ 
171+     public  constructor ( 
172+         public  readonly  parent : AWSTreeNodeBase , 
173+         public  override  readonly  regionCode : string , 
174+         public  details : StepFunctions . ExecutionListItem 
175+     )  { 
176+         super ( '' ) 
177+         this . update ( details ) 
178+         this . contextValue  =  StateMachineExecutionNode . contextValue 
179+     } 
180+ 
181+     public  update ( details : StepFunctions . ExecutionListItem ) : void { 
182+         this . details  =  details 
183+         this . label  =  this . details . name  ||  '' 
184+         this . tooltip  =  this . getToolTip ( this . details ) 
185+         this . iconPath  =  this . getIconPathForStatus ( this . details . status ) 
186+     } 
187+ 
188+     public  get  arn ( ) : string  { 
189+         return  this . details . executionArn  ||  '' 
190+     } 
123191
124-     return  node 
192+     public  get  name ( ) : string  { 
193+         return  this . details . name  ||  '' 
194+     } 
195+ 
196+     private  getIconPathForStatus ( status ?: string ) : IconPath  { 
197+         switch  ( status )  { 
198+             case  'RUNNING' :
199+                 return  getIcon ( 'vscode-sync' ) 
200+             case  'SUCCEEDED' :
201+                 return  getIcon ( 'vscode-check' ) 
202+             default :
203+                 return  getIcon ( 'vscode-error' ) 
204+         } 
205+     } 
206+ 
207+     private  getToolTip ( details : StepFunctions . ExecutionListItem )  { 
208+         const  startTimeText  =  localize ( 'AWS.explorerNode.stepfunctions.startTime' ,  'Start Time' ) 
209+         const  endTimeText  =  localize ( 'AWS.explorerNode.stepfunctions.endTime' ,  'End Time' ) 
210+         const  durationText  =  localize ( 'AWS.explorerNode.stepfunctions.duration' ,  'Duration' ) 
211+         const  secondsText  =  localize ( 'AWS.explorerNode.stepfunctions.seconds' ,  'seconds' ) 
212+ 
213+         let  text : string  =  `${ details . status } ${ os . EOL } ${ startTimeText } ${ details . startDate ?. toLocaleString ( ) } ${ os . EOL }  
214+         if  ( details . status  !==  'RUNNING' )  { 
215+             text  +=  `${ endTimeText } ${ details . stopDate ?. toLocaleString ( ) } ${ os . EOL }  
216+             const  endDate  =  details . stopDate  ? details . stopDate  : new  Date ( ) 
217+             text  +=  `${ durationText } ${ Math . trunc ( ( endDate . getTime ( )  -  details . startDate ! . getTime ( ) )  /  1000 ) } ${ secondsText } ${ os . EOL }  
218+         } 
219+         return  text 
220+     } 
125221} 
0 commit comments