11import { Flags } from '@oclif/core'
2- import cliProgress from 'cli-progress'
2+ import { MultiBar , Presets , SingleBar } from 'cli-progress'
33
44import { ScCommand } from '../../../sc-command.js'
5- import { EventBrokerListApiResponse , OperationData , OperationResponse } from '../../../types/broker.js'
5+ import { AllOperationResponse , EventBrokerListApiResponse , OperationData , OperationResponse } from '../../../types/broker.js'
6+ import { renderTable , sleep } from '../../../util/internal.js'
67import { ScConnection } from '../../../util/sc-connection.js'
7- import { camelCaseToTitleCase , renderKeyValueTable , sleep } from '../../../util/internal.js'
88
99export default class MissionctrlBrokerOpstatus extends ScCommand < typeof MissionctrlBrokerOpstatus > {
1010 static override args = { }
11- static override description = `Get the status of an operation that being performed on an event broker service.
12- To get the operation, you provide identifier of the operation and the identifier of the event broker service.
11+ static override description = `Get the status of all operations being performed on an event broker service.
12+ To get the operation status , you must provide the identifier or name of the event broker service.
1313
1414 Token Permissions: [ mission_control:access or services:get or services:get:self or services:view or services:view:self ]`
1515 static override examples = [
16- '<%= config.bin %> <%= command.id %>' ,
16+ '<%= config.bin %> <%= command.id %> -b <broker-id>' ,
17+ '<%= config.bin %> <%= command.id %> -n <broker-name>' ,
1718 ]
1819 static override flags = {
1920 'broker-id' : Flags . string ( {
@@ -26,32 +27,27 @@ export default class MissionctrlBrokerOpstatus extends ScCommand<typeof Missionc
2627 description : 'Name of the event broker service.' ,
2728 exactlyOne : [ 'broker-id' , 'name' ] ,
2829 } ) ,
29- 'operation-id' : Flags . string ( {
30- char : 'o' ,
31- description : 'The identifier of the operation being performed on the event broker service.'
32- } ) ,
3330 'show-progress' : Flags . boolean ( {
3431 char : 'p' ,
35- description : 'Displays a status bar of the in-progress operation . The command will wait for completion of each step of the operation.'
32+ description : 'Displays a status bar of the in-progress operations . The command will wait for completion of each step of the operation.'
3633 } ) ,
3734 'wait-ms' : Flags . integer ( {
3835 char : 'w' ,
39- description : 'The milliseconds to wait between API call in when showing progress. Default is 5000 ms.'
36+ description : 'The milliseconds to wait between API calls for checking progress of the operation . Default is 5000 ms.'
4037 } ) ,
4138 }
4239
43- public async run ( ) : Promise < OperationData > {
40+ public async run ( ) : Promise < OperationData [ ] > {
4441 const { flags } = await this . parse ( MissionctrlBrokerOpstatus )
4542
4643 const name = flags . name ?? ''
4744 let brokerId = flags [ 'broker-id' ] ?? ''
48- const operationId = flags [ 'operation-id' ] ?? ''
4945 const showProgress = flags [ 'show-progress' ] ?? false
5046 const waitMs = flags [ 'wait-ms' ] ?? 5000
5147
5248 const conn = new ScConnection ( )
5349
54- // API url
50+ // Base API url
5551 let apiUrl : string = `/missionControl/eventBrokerServices`
5652
5753 // If broker name provided, retrieve the broker service id first
@@ -60,7 +56,7 @@ export default class MissionctrlBrokerOpstatus extends ScCommand<typeof Missionc
6056 // API call to get broker by name
6157 apiUrl += `?customAttributes=name=="${ name } "`
6258 const resp = await conn . get < EventBrokerListApiResponse > ( apiUrl )
63- // TODO FUTURE: show status of multiple brokers operations that match the name
59+ // FUTURE: show status of multiple brokers operations that match the name
6460 if ( resp . data . length > 1 ) {
6561 this . error ( `Multiple broker services found with: ${ name } . Exactly one broker service must match the provided name.` )
6662 } else {
@@ -69,59 +65,107 @@ export default class MissionctrlBrokerOpstatus extends ScCommand<typeof Missionc
6965 }
7066
7167 // API call to retrieve status of the broker operation
72- apiUrl = `/missionControl/eventBrokerServices/${ brokerId } /operations/${ operationId } `
73- if ( showProgress ) {
74- apiUrl += '?expand=progressLogs'
75- }
76- let resp = await conn . get < OperationResponse > ( apiUrl )
77- this . print ( resp . data )
78-
79- // Display progress bar for each step included in the progress logs
80- // Enable progress bar if set
81- if ( showProgress && resp . data . progressLogs && resp . data . progressLogs . length > 0 ) {
82- let progressLogs = resp . data . progressLogs
83- let numSteps = progressLogs . length
84-
85- // Create a new progress bar instance and use shades_classic theme
86- const progressBar = new cliProgress . SingleBar ( { } , cliProgress . Presets . shades_classic ) ;
87-
88- // start the progress bar with a total value of size of the steps and start value of 0
89- progressBar . start ( numSteps , 0 ) ;
68+ apiUrl = `/missionControl/eventBrokerServices/${ brokerId } /operations`
69+
70+ const resp = await conn . get < AllOperationResponse > ( apiUrl )
71+ const opStatusArray = [
72+ [ 'Operation Id' , 'Operation Type' , 'Status' , 'Created Time' , 'Completed Time' ] ,
73+ ...resp . data . map ( ( item : OperationData ) => [
74+ item . id ,
75+ item . operationType ,
76+ item . status ,
77+ item . createdTime ,
78+ item . completedTime ,
79+ ] ) ,
80+ ]
9081
91- // Update the progress with the steps completed
92- let completedNumSteps = 0
93- while ( completedNumSteps < numSteps ) {
94- // Wait before making the next API call
95- await sleep ( waitMs )
96- // Make another API call to get the lastest progress
97- resp = await conn . get < OperationResponse > ( apiUrl )
98- if ( resp . data . progressLogs ) {
99- progressLogs = resp . data . progressLogs
100- for ( const progressLog of progressLogs ) {
101- if ( progressLog . step === 'success' ) {
102- completedNumSteps ++
103- }
104- }
105- // Update progress bar
82+ // Display results as a table
83+ this . log ( renderTable ( opStatusArray ) )
84+
85+ // If show-progress flag is set, display progress bars for each operation
86+ if ( showProgress && resp . data . length > 0 ) {
87+ // Create progress bar for each operation
88+ const multiProgressBar = new MultiBar ( {
89+ clearOnComplete : false ,
90+ format : ' {bar} | {operationType} | {value}/{total}' ,
91+ hideCursor : true ,
92+ } , Presets . shades_classic )
93+
94+ // Get the initial progress for each operation
95+ const progressBars : [ string , SingleBar ] [ ] = [ ]
96+ let completedOperations = 0
97+ let allCompleted = false
98+ for ( const operationData of resp . data ) {
99+ const opStatusApiUrl = `/missionControl/eventBrokerServices/${ brokerId } /operations/${ operationData . id } ?expand=progressLogs`
100+ // eslint-disable-next-line no-await-in-loop
101+ const opStatusResp = await conn . get < OperationResponse > ( opStatusApiUrl )
102+ this . debug ( `Operation ID: ${ operationData . id } , Type: ${ operationData . operationType } , Status: ${ operationData . status } ` )
103+ if ( opStatusResp . data . progressLogs ) {
104+ const numSteps = opStatusResp . data . progressLogs . length
105+ // start a new progress bar for the operation with a total value of size of the steps
106+ const progressBar = multiProgressBar . create ( numSteps , 0 , { operationType : operationData . operationType } )
107+ // Update the progress with the steps completed
108+ const completedNumSteps = opStatusResp . data . progressLogs . filter ( log => log . status === 'success' ) . length
106109 progressBar . update ( completedNumSteps )
107- } else {
108- break
110+ if ( completedNumSteps === numSteps || opStatusResp . data . status === 'SUCCEEDED' || opStatusResp . data . status === 'FAILED' ) {
111+ completedOperations += 1
112+ progressBar . stop ( )
113+ }
114+
115+ // Add the operation ID and progress bar to the list
116+ progressBars . push ( [ operationData . id , progressBar ] )
109117 }
110118 }
111119
112- // stop the progress bar
113- progressBar . stop ( )
120+ // Check if all operations are completed
121+ if ( completedOperations === progressBars . length ) {
122+ allCompleted = true
123+ }
124+
125+ // Loop until all operations are completed
126+ while ( ! allCompleted ) {
127+ // Wait before making the next API call
128+ sleep ( waitMs )
129+ // Poll the status of all operations and update the progress bars
130+ // eslint-disable-next-line no-await-in-loop
131+ allCompleted = await this . pollAllOperationStatus ( conn , brokerId , progressBars )
132+ }
133+
134+ multiProgressBar . stop ( )
135+ this . log ( ) // Add a new line for better readability
114136 }
115137
116138 return resp . data
117139 }
118140
119- private print ( environment : OperationData ) : void {
120- const tableRows = [
121- [ 'Key' , 'Value' ] ,
122- ...Object . entries ( environment ) . map ( ( [ key , value ] ) => [ camelCaseToTitleCase ( key ) , value ] ) ,
123- ]
124- this . log ( )
125- this . log ( renderKeyValueTable ( tableRows ) )
141+ private async pollAllOperationStatus ( conn : ScConnection , brokerId : string , progressBars : [ string , SingleBar ] [ ] ) : Promise < boolean > {
142+ let completedOperations = 0
143+ let allCompleted = false
144+ // For each operation, get the latest status and update the progress bar
145+ for ( const [ operationId , progressBar ] of progressBars ) {
146+ const opStatusApiUrl = `/missionControl/eventBrokerServices/${ brokerId } /operations/${ operationId } ?expand=progressLogs`
147+ // eslint-disable-next-line no-await-in-loop
148+ const opStatusResp = await conn . get < OperationResponse > ( opStatusApiUrl )
149+ if ( opStatusResp . data . progressLogs ) {
150+ const numSteps = opStatusResp . data . progressLogs . length
151+ const completedNumSteps = opStatusResp . data . progressLogs . filter ( log => log . status === 'success' ) . length
152+ // Update progress bar
153+ progressBar . setTotal ( numSteps )
154+ progressBar . update ( completedNumSteps )
155+ if ( completedNumSteps === numSteps || opStatusResp . data . status === 'SUCCEEDED' || opStatusResp . data . status === 'FAILED' ) {
156+ completedOperations += 1
157+ progressBar . stop ( )
158+ }
159+ } else {
160+ progressBar . stop ( )
161+ }
162+ }
163+
164+ // Check if all operations are completed
165+ if ( completedOperations === progressBars . length ) {
166+ allCompleted = true
167+ }
168+
169+ return allCompleted
126170 }
127- }
171+ }
0 commit comments