1+ /* eslint-disable max-lines */
12import PropTypes from 'prop-types' ;
2- import React , { useEffect , useState } from 'react' ;
3+ import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
34import { useDispatch , useSelector } from 'react-redux' ;
45import { Button , Split , SplitItem } from '@patternfly/react-core' ;
56import { UndoIcon } from '@patternfly/react-icons' ;
@@ -44,21 +45,32 @@ const JobInvocationToolbarButtons = ({ jobId, data }) => {
4445 const [ isActionOpen , setIsActionOpen ] = useState ( false ) ;
4546 const [ reportTemplateJobId , setReportTemplateJobId ] = useState ( undefined ) ;
4647 const [ templateInputId , setTemplateInputId ] = useState ( undefined ) ;
47- const queryParams = new URLSearchParams ( {
48- [ `report_template_report[input_values][${ templateInputId } ][value]` ] : jobId ,
49- } ) ;
5048 const dispatch = useDispatch ( ) ;
49+ const reportHref = useMemo ( ( ) => {
50+ if ( reportTemplateJobId === undefined || templateInputId === undefined ) {
51+ return undefined ;
52+ }
53+ const queryParams = new URLSearchParams ( {
54+ [ `report_template_report[input_values][${ templateInputId } ][value]` ] : jobId ,
55+ } ) ;
56+ return foremanUrl (
57+ `/templates/report_templates/${ reportTemplateJobId } /generate?${ queryParams . toString ( ) } `
58+ ) ;
59+ } , [ jobId , reportTemplateJobId , templateInputId ] ) ;
5160
52- const onActionFocus = ( ) => {
61+ const onActionFocus = useCallback ( ( ) => {
5362 const element = document . getElementById (
5463 `toggle-split-button-action-primary-${ jobId } `
5564 ) ;
56- element . focus ( ) ;
57- } ;
58- const onActionSelect = ( ) => {
65+ if ( element ) {
66+ element . focus ( ) ;
67+ }
68+ } , [ jobId ] ) ;
69+ const onActionSelect = useCallback ( ( ) => {
5970 setIsActionOpen ( false ) ;
6071 onActionFocus ( ) ;
61- } ;
72+ } , [ onActionFocus ] ) ;
73+ const onActionToggle = useCallback ( ( _event , val ) => setIsActionOpen ( val ) , [ ] ) ;
6274
6375 useEffect ( ( ) => {
6476 let isMounted = true ;
@@ -112,102 +124,151 @@ const JobInvocationToolbarButtons = ({ jobId, data }) => {
112124 } ;
113125 } , [ dispatch , reportTemplateJobId ] ) ;
114126
115- const recurrenceDropdownItems = recurrence
116- ? [
117- < DropdownSeparator ouiaId = "dropdown-separator-1" key = "separator-1" /> ,
118- < DropdownItem
119- ouiaId = "change-enabled-recurring-dropdown-item"
120- onClick = { ( ) =>
121- dispatch (
122- enableRecurringLogic ( recurrence ?. id , recurringEnabled , jobId )
123- )
124- }
125- key = "change-enabled-recurring"
126- component = "button"
127- isDisabled = {
128- recurrence ?. id === undefined ||
129- recurrence ?. state === 'cancelled' ||
130- ! canEditRecurringLogic
131- }
132- >
133- { recurringEnabled ? __ ( 'Disable recurring' ) : __ ( 'Enable recurring' ) }
134- </ DropdownItem > ,
135- < DropdownItem
136- ouiaId = "cancel-recurring-dropdown-item"
137- onClick = { ( ) => dispatch ( cancelRecurringLogic ( recurrence ?. id , jobId ) ) }
138- key = "cancel-recurring"
139- component = "button"
140- isDisabled = {
141- recurrence ?. id === undefined ||
142- recurrence ?. state === 'cancelled' ||
143- ! canEditRecurringLogic
144- }
145- >
146- { __ ( 'Cancel recurring' ) }
147- </ DropdownItem > ,
148- ]
149- : [ ] ;
127+ const recurrenceDropdownItems = useMemo (
128+ ( ) =>
129+ recurrence
130+ ? [
131+ < DropdownSeparator
132+ ouiaId = "dropdown-separator-1"
133+ key = "separator-1"
134+ /> ,
135+ < DropdownItem
136+ ouiaId = "change-enabled-recurring-dropdown-item"
137+ onClick = { ( ) =>
138+ dispatch (
139+ enableRecurringLogic ( recurrence ?. id , recurringEnabled , jobId )
140+ )
141+ }
142+ key = "change-enabled-recurring"
143+ component = "button"
144+ isDisabled = {
145+ recurrence ?. id === undefined ||
146+ recurrence ?. state === 'cancelled' ||
147+ ! canEditRecurringLogic
148+ }
149+ >
150+ { recurringEnabled
151+ ? __ ( 'Disable recurring' )
152+ : __ ( 'Enable recurring' ) }
153+ </ DropdownItem > ,
154+ < DropdownItem
155+ ouiaId = "cancel-recurring-dropdown-item"
156+ onClick = { ( ) =>
157+ dispatch ( cancelRecurringLogic ( recurrence ?. id , jobId ) )
158+ }
159+ key = "cancel-recurring"
160+ component = "button"
161+ isDisabled = {
162+ recurrence ?. id === undefined ||
163+ recurrence ?. state === 'cancelled' ||
164+ ! canEditRecurringLogic
165+ }
166+ >
167+ { __ ( 'Cancel recurring' ) }
168+ </ DropdownItem > ,
169+ ]
170+ : [ ] ,
171+ [ recurrence , recurringEnabled , canEditRecurringLogic , dispatch , jobId ]
172+ ) ;
150173
151- const dropdownItems = [
152- < DropdownItem
153- ouiaId = "rerun-succeeded-dropdown-item"
154- href = { foremanUrl ( `/job_invocations/${ jobId } /rerun?succeeded_only=1` ) }
155- key = "rerun-succeeded"
156- isDisabled = { ! canCreateJobInvocations || ! ( succeeded > 0 ) }
157- description = "Rerun job on successful hosts"
158- >
159- { __ ( 'Rerun successful' ) }
160- </ DropdownItem > ,
161- < DropdownItem
162- ouiaId = "rerun-failed-dropdown-item"
163- href = { foremanUrl ( `/job_invocations/${ jobId } /rerun?failed_only=1` ) }
164- key = "rerun-failed"
165- isDisabled = { ! canCreateJobInvocations || ! ( failed > 0 ) }
166- description = "Rerun job on failed hosts"
167- >
168- { __ ( 'Rerun failed' ) }
169- </ DropdownItem > ,
170- < DropdownItem
171- ouiaId = "view-task-dropdown-item"
172- href = { foremanUrl ( `/foreman_tasks/tasks/${ task ?. id } ` ) }
173- key = "view-task"
174- isDisabled = { ! canViewForemanTasks || task === undefined }
175- description = "See details of latest task"
176- >
177- { __ ( 'View task' ) }
178- </ DropdownItem > ,
179- < DropdownSeparator ouiaId = "dropdown-separator-0" key = "separator-0" /> ,
180- < DropdownItem
181- ouiaId = "cancel-dropdown-item"
182- onClick = { ( ) => dispatch ( cancelJob ( jobId , false ) ) }
183- key = "cancel"
184- component = "button"
185- isDisabled = { ! canCancelJobInvocations || ! isTaskCancelable }
186- description = "Cancel job gracefully"
187- >
188- { __ ( 'Cancel' ) }
189- </ DropdownItem > ,
190- < DropdownItem
191- ouiaId = "abort-dropdown-item"
192- onClick = { ( ) => dispatch ( cancelJob ( jobId , true ) ) }
193- key = "abort"
194- component = "button"
195- isDisabled = { ! canCancelJobInvocations || ! isTaskCancelable }
196- description = "Cancel job immediately"
197- >
198- { __ ( 'Abort' ) }
199- </ DropdownItem > ,
200- ...recurrenceDropdownItems ,
201- < DropdownSeparator ouiaId = "dropdown-separator-2" key = "separator-2" /> ,
202- < DropdownItem
203- ouiaId = "legacy-ui-dropdown-item"
204- icon = { < UndoIcon /> }
205- href = { `/legacy/job_invocations/${ jobId } ` }
206- key = "legacy-ui"
207- >
208- { __ ( 'Legacy UI' ) }
209- </ DropdownItem > ,
210- ] ;
174+ const dropdownItems = useMemo (
175+ ( ) => [
176+ < DropdownItem
177+ ouiaId = "rerun-succeeded-dropdown-item"
178+ href = { foremanUrl ( `/job_invocations/${ jobId } /rerun?succeeded_only=1` ) }
179+ key = "rerun-succeeded"
180+ isDisabled = { ! canCreateJobInvocations || ! ( succeeded > 0 ) }
181+ description = "Rerun job on successful hosts"
182+ >
183+ { __ ( 'Rerun successful' ) }
184+ </ DropdownItem > ,
185+ < DropdownItem
186+ ouiaId = "rerun-failed-dropdown-item"
187+ href = { foremanUrl ( `/job_invocations/${ jobId } /rerun?failed_only=1` ) }
188+ key = "rerun-failed"
189+ isDisabled = { ! canCreateJobInvocations || ! ( failed > 0 ) }
190+ description = "Rerun job on failed hosts"
191+ >
192+ { __ ( 'Rerun failed' ) }
193+ </ DropdownItem > ,
194+ < DropdownItem
195+ ouiaId = "view-task-dropdown-item"
196+ href = { foremanUrl ( `/foreman_tasks/tasks/${ task ?. id } ` ) }
197+ key = "view-task"
198+ isDisabled = { ! canViewForemanTasks || task === undefined }
199+ description = "See details of latest task"
200+ >
201+ { __ ( 'View task' ) }
202+ </ DropdownItem > ,
203+ < DropdownSeparator ouiaId = "dropdown-separator-0" key = "separator-0" /> ,
204+ < DropdownItem
205+ ouiaId = "cancel-dropdown-item"
206+ onClick = { ( ) => dispatch ( cancelJob ( jobId , false ) ) }
207+ key = "cancel"
208+ component = "button"
209+ isDisabled = { ! canCancelJobInvocations || ! isTaskCancelable }
210+ description = "Cancel job gracefully"
211+ >
212+ { __ ( 'Cancel' ) }
213+ </ DropdownItem > ,
214+ < DropdownItem
215+ ouiaId = "abort-dropdown-item"
216+ onClick = { ( ) => dispatch ( cancelJob ( jobId , true ) ) }
217+ key = "abort"
218+ component = "button"
219+ isDisabled = { ! canCancelJobInvocations || ! isTaskCancelable }
220+ description = "Cancel job immediately"
221+ >
222+ { __ ( 'Abort' ) }
223+ </ DropdownItem > ,
224+ ...recurrenceDropdownItems ,
225+ < DropdownSeparator ouiaId = "dropdown-separator-2" key = "separator-2" /> ,
226+ < DropdownItem
227+ ouiaId = "legacy-ui-dropdown-item"
228+ icon = { < UndoIcon /> }
229+ href = { `/legacy/job_invocations/${ jobId } ` }
230+ key = "legacy-ui"
231+ >
232+ { __ ( 'Legacy UI' ) }
233+ </ DropdownItem > ,
234+ ] ,
235+ [
236+ canCancelJobInvocations ,
237+ canCreateJobInvocations ,
238+ canViewForemanTasks ,
239+ dispatch ,
240+ failed ,
241+ isTaskCancelable ,
242+ jobId ,
243+ recurrenceDropdownItems ,
244+ succeeded ,
245+ task ,
246+ ]
247+ ) ;
248+
249+ const dropdownToggle = useMemo (
250+ ( ) => (
251+ < DropdownToggle
252+ ouiaId = "toggle-button-action-primary"
253+ id = { `toggle-split-button-action-primary-${ jobId } ` }
254+ splitButtonItems = { [
255+ < Button
256+ component = "a"
257+ ouiaId = "button-rerun-all"
258+ key = "rerun"
259+ href = { foremanUrl ( `/job_invocations/${ jobId } /rerun` ) }
260+ variant = "control"
261+ isDisabled = { ! canCreateJobInvocations }
262+ >
263+ { __ ( `Rerun all` ) }
264+ </ Button > ,
265+ ] }
266+ splitButtonVariant = "action"
267+ onToggle = { onActionToggle }
268+ />
269+ ) ,
270+ [ canCreateJobInvocations , jobId , onActionToggle ]
271+ ) ;
211272
212273 return (
213274 < >
@@ -217,14 +278,12 @@ const JobInvocationToolbarButtons = ({ jobId, data }) => {
217278 component = "a"
218279 ouiaId = "button-create-report"
219280 className = "button-create-report"
220- href = { foremanUrl (
221- `/templates/report_templates/${ reportTemplateJobId } /generate?${ queryParams . toString ( ) } `
222- ) }
281+ href = { reportHref }
223282 variant = "secondary"
224283 isDisabled = {
225284 ! canGenerateReportTemplates ||
226285 task ?. state === STATUS . PENDING ||
227- templateInputId === undefined
286+ reportHref === undefined
228287 }
229288 >
230289 { __ ( `Create report` ) }
@@ -235,26 +294,7 @@ const JobInvocationToolbarButtons = ({ jobId, data }) => {
235294 ouiaId = "job-invocation-global-actions-dropdown"
236295 onSelect = { onActionSelect }
237296 position = { DropdownPosition . right }
238- toggle = {
239- < DropdownToggle
240- ouiaId = "toggle-button-action-primary"
241- id = { `toggle-split-button-action-primary-${ jobId } ` }
242- splitButtonItems = { [
243- < Button
244- component = "a"
245- ouiaId = "button-rerun-all"
246- key = "rerun"
247- href = { foremanUrl ( `/job_invocations/${ jobId } /rerun` ) }
248- variant = "control"
249- isDisabled = { ! canCreateJobInvocations }
250- >
251- { __ ( `Rerun all` ) }
252- </ Button > ,
253- ] }
254- splitButtonVariant = "action"
255- onToggle = { ( _event , val ) => setIsActionOpen ( val ) }
256- />
257- }
297+ toggle = { dropdownToggle }
258298 isOpen = { isActionOpen }
259299 dropdownItems = { dropdownItems }
260300 />
0 commit comments