@@ -11,12 +11,13 @@ import {
1111 EuiButtonEmpty ,
1212 EuiFlexItem ,
1313 EuiFlexGroup ,
14- EuiFlyout ,
1514 EuiFlyoutBody ,
1615 EuiFlyoutFooter ,
1716 EuiFlyoutHeader ,
1817 EuiSwitch ,
1918 EuiTitle ,
19+ EuiResizeObserver ,
20+ EuiProgress ,
2021} from '@elastic/eui' ;
2122import { NewSelectionIdBadges } from './new_selection_id_badges' ;
2223// @ts -ignore
@@ -39,7 +40,6 @@ export interface JobSelectorFlyoutProps {
3940 newSelection ?: string [ ] ;
4041 onFlyoutClose : ( ) => void ;
4142 onJobsFetched ?: ( maps : JobSelectionMaps ) => void ;
42- onSelectionChange ?: ( newSelection : string [ ] ) => void ;
4343 onSelectionConfirmed : ( payload : {
4444 newSelection : string [ ] ;
4545 jobIds : string [ ] ;
@@ -52,13 +52,12 @@ export interface JobSelectorFlyoutProps {
5252 withTimeRangeSelector ?: boolean ;
5353}
5454
55- export const JobSelectorFlyout : FC < JobSelectorFlyoutProps > = ( {
55+ export const JobSelectorFlyoutContent : FC < JobSelectorFlyoutProps > = ( {
5656 dateFormatTz,
5757 selectedIds = [ ] ,
5858 singleSelection,
5959 timeseriesOnly,
6060 onJobsFetched,
61- onSelectionChange,
6261 onSelectionConfirmed,
6362 onFlyoutClose,
6463 maps,
@@ -73,14 +72,15 @@ export const JobSelectorFlyout: FC<JobSelectorFlyoutProps> = ({
7372
7473 const [ newSelection , setNewSelection ] = useState ( selectedIds ) ;
7574
75+ const [ isLoading , setIsLoading ] = useState ( true ) ;
7676 const [ showAllBadges , setShowAllBadges ] = useState ( false ) ;
7777 const [ applyTimeRange , setApplyTimeRange ] = useState ( true ) ;
7878 const [ jobs , setJobs ] = useState < MlJobWithTimeRange [ ] > ( [ ] ) ;
7979 const [ groups , setGroups ] = useState < any [ ] > ( [ ] ) ;
8080 const [ ganttBarWidth , setGanttBarWidth ] = useState ( DEFAULT_GANTT_BAR_WIDTH ) ;
8181 const [ jobGroupsMaps , setJobGroupsMaps ] = useState ( maps ) ;
8282
83- const flyoutEl = useRef < { flyout : HTMLElement } > ( null ) ;
83+ const flyoutEl = useRef < HTMLElement | null > ( null ) ;
8484
8585 function applySelection ( ) {
8686 // allNewSelection will be a list of all job ids (including those from groups) selected from the table
@@ -131,19 +131,19 @@ export const JobSelectorFlyout: FC<JobSelectorFlyoutProps> = ({
131131 // Wrap handleResize in useCallback as it is a dependency for useEffect on line 131 below.
132132 // Not wrapping it would cause this dependency to change on every render
133133 const handleResize = useCallback ( ( ) => {
134- if ( jobs . length > 0 && flyoutEl && flyoutEl . current && flyoutEl . current . flyout ) {
135- // get all cols in flyout table
136- const tableHeaderCols : NodeListOf < HTMLElement > = flyoutEl . current . flyout . querySelectorAll (
137- 'table thead th'
138- ) ;
139- // get the width of the last col
140- const derivedWidth = tableHeaderCols [ tableHeaderCols . length - 1 ] . offsetWidth - 16 ;
141- const normalizedJobs = normalizeTimes ( jobs , dateFormatTz , derivedWidth ) ;
142- setJobs ( normalizedJobs ) ;
143- const { groups : updatedGroups } = getGroupsFromJobs ( normalizedJobs ) ;
144- setGroups ( updatedGroups ) ;
145- setGanttBarWidth ( derivedWidth ) ;
146- }
134+ if ( jobs . length === 0 || ! flyoutEl . current ) return ;
135+
136+ // get all cols in flyout table
137+ const tableHeaderCols : NodeListOf < HTMLElement > = flyoutEl . current . querySelectorAll (
138+ 'table thead th'
139+ ) ;
140+ // get the width of the last col
141+ const derivedWidth = tableHeaderCols [ tableHeaderCols . length - 1 ] . offsetWidth - 16 ;
142+ const normalizedJobs = normalizeTimes ( jobs , dateFormatTz , derivedWidth ) ;
143+ setJobs ( normalizedJobs ) ;
144+ const { groups : updatedGroups } = getGroupsFromJobs ( normalizedJobs ) ;
145+ setGroups ( updatedGroups ) ;
146+ setGanttBarWidth ( derivedWidth ) ;
147147 } , [ dateFormatTz , jobs ] ) ;
148148
149149 // Fetch jobs list on flyout open
@@ -172,119 +172,124 @@ export const JobSelectorFlyout: FC<JobSelectorFlyoutProps> = ({
172172 } ) ,
173173 } ) ;
174174 }
175+ setIsLoading ( false ) ;
175176 }
176177
177- useEffect ( ( ) => {
178- // Ensure ganttBar width gets calculated on resize
179- window . addEventListener ( 'resize' , handleResize ) ;
180-
181- return ( ) => {
182- window . removeEventListener ( 'resize' , handleResize ) ;
183- } ;
184- } , [ handleResize ] ) ;
185-
186- useEffect ( ( ) => {
187- handleResize ( ) ;
188- } , [ handleResize , jobs ] ) ;
189-
190178 return (
191- < EuiFlyout
192- // @ts -ignore
193- ref = { flyoutEl }
194- onClose = { onFlyoutClose }
195- aria-labelledby = "jobSelectorFlyout"
196- data-test-subj = "mlFlyoutJobSelector"
197- >
198- < EuiFlyoutHeader hasBorder >
199- < EuiTitle size = "m" >
200- < h2 id = "flyoutTitle" >
201- { i18n . translate ( 'xpack.ml.jobSelector.flyoutTitle' , {
202- defaultMessage : 'Job selection' ,
203- } ) }
204- </ h2 >
205- </ EuiTitle >
206- </ EuiFlyoutHeader >
207- < EuiFlyoutBody className = "mlJobSelectorFlyoutBody" >
208- < EuiFlexGroup direction = "column" responsive = { false } >
209- < EuiFlexItem grow = { false } >
210- < EuiFlexGroup wrap responsive = { false } gutterSize = "xs" alignItems = "center" >
211- < NewSelectionIdBadges
212- limit = { BADGE_LIMIT }
213- maps = { jobGroupsMaps }
214- newSelection = { newSelection }
215- onDeleteClick = { removeId }
216- onLinkClick = { ( ) => setShowAllBadges ( ! showAllBadges ) }
217- showAllBadges = { showAllBadges }
218- />
219- </ EuiFlexGroup >
220- </ EuiFlexItem >
221- < EuiFlexItem grow = { false } >
222- < EuiFlexGroup direction = "row" justifyContent = "spaceBetween" responsive = { false } >
179+ < EuiResizeObserver onResize = { handleResize } >
180+ { ( resizeRef ) => (
181+ < EuiFlexGroup
182+ direction = "column"
183+ gutterSize = "none"
184+ ref = { ( e ) => {
185+ flyoutEl . current = e ;
186+ resizeRef ( e ) ;
187+ } }
188+ aria-labelledby = "jobSelectorFlyout"
189+ data-test-subj = "mlFlyoutJobSelector"
190+ >
191+ < EuiFlyoutHeader hasBorder >
192+ < EuiTitle size = "m" >
193+ < h2 id = "flyoutTitle" >
194+ { i18n . translate ( 'xpack.ml.jobSelector.flyoutTitle' , {
195+ defaultMessage : 'Job selection' ,
196+ } ) }
197+ </ h2 >
198+ </ EuiTitle >
199+ </ EuiFlyoutHeader >
200+ < EuiFlyoutBody className = "mlJobSelectorFlyoutBody" >
201+ { isLoading ? (
202+ < EuiProgress size = "xs" color = "accent" />
203+ ) : (
204+ < >
205+ < EuiFlexGroup direction = "column" responsive = { false } >
206+ < EuiFlexItem grow = { false } >
207+ < EuiFlexGroup wrap responsive = { false } gutterSize = "xs" alignItems = "center" >
208+ < NewSelectionIdBadges
209+ limit = { BADGE_LIMIT }
210+ maps = { jobGroupsMaps }
211+ newSelection = { newSelection }
212+ onDeleteClick = { removeId }
213+ onLinkClick = { ( ) => setShowAllBadges ( ! showAllBadges ) }
214+ showAllBadges = { showAllBadges }
215+ />
216+ </ EuiFlexGroup >
217+ </ EuiFlexItem >
218+ < EuiFlexItem grow = { false } >
219+ < EuiFlexGroup direction = "row" justifyContent = "spaceBetween" responsive = { false } >
220+ < EuiFlexItem grow = { false } >
221+ { ! singleSelection && newSelection . length > 0 && (
222+ < EuiButtonEmpty
223+ onClick = { clearSelection }
224+ size = "xs"
225+ data-test-subj = "mlFlyoutJobSelectorButtonClearSelection"
226+ >
227+ { i18n . translate ( 'xpack.ml.jobSelector.clearAllFlyoutButton' , {
228+ defaultMessage : 'Clear all' ,
229+ } ) }
230+ </ EuiButtonEmpty >
231+ ) }
232+ </ EuiFlexItem >
233+ { withTimeRangeSelector && (
234+ < EuiFlexItem grow = { false } >
235+ < EuiSwitch
236+ label = { i18n . translate (
237+ 'xpack.ml.jobSelector.applyTimerangeSwitchLabel' ,
238+ {
239+ defaultMessage : 'Apply time range' ,
240+ }
241+ ) }
242+ checked = { applyTimeRange }
243+ onChange = { toggleTimerangeSwitch }
244+ data-test-subj = "mlFlyoutJobSelectorSwitchApplyTimeRange"
245+ />
246+ </ EuiFlexItem >
247+ ) }
248+ </ EuiFlexGroup >
249+ </ EuiFlexItem >
250+ </ EuiFlexGroup >
251+ < JobSelectorTable
252+ jobs = { jobs }
253+ ganttBarWidth = { ganttBarWidth }
254+ groupsList = { groups }
255+ onSelection = { handleNewSelection }
256+ selectedIds = { newSelection }
257+ singleSelection = { singleSelection }
258+ timeseriesOnly = { timeseriesOnly }
259+ withTimeRangeSelector = { withTimeRangeSelector }
260+ />
261+ </ >
262+ ) }
263+ </ EuiFlyoutBody >
264+ < EuiFlyoutFooter >
265+ < EuiFlexGroup >
223266 < EuiFlexItem grow = { false } >
224- { ! singleSelection && newSelection . length > 0 && (
225- < EuiButtonEmpty
226- onClick = { clearSelection }
227- size = "xs"
228- data-test-subj = "mlFlyoutJobSelectorButtonClearSelection"
229- >
230- { i18n . translate ( 'xpack.ml.jobSelector.clearAllFlyoutButton' , {
231- defaultMessage : 'Clear all' ,
232- } ) }
233- </ EuiButtonEmpty >
234- ) }
267+ < EuiButton
268+ onClick = { applySelection }
269+ fill
270+ isDisabled = { newSelection . length === 0 }
271+ data-test-subj = "mlFlyoutJobSelectorButtonApply"
272+ >
273+ { i18n . translate ( 'xpack.ml.jobSelector.applyFlyoutButton' , {
274+ defaultMessage : 'Apply' ,
275+ } ) }
276+ </ EuiButton >
277+ </ EuiFlexItem >
278+ < EuiFlexItem grow = { false } >
279+ < EuiButtonEmpty
280+ iconType = "cross"
281+ onClick = { onFlyoutClose }
282+ data-test-subj = "mlFlyoutJobSelectorButtonClose"
283+ >
284+ { i18n . translate ( 'xpack.ml.jobSelector.closeFlyoutButton' , {
285+ defaultMessage : 'Close' ,
286+ } ) }
287+ </ EuiButtonEmpty >
235288 </ EuiFlexItem >
236- { withTimeRangeSelector && (
237- < EuiFlexItem grow = { false } >
238- < EuiSwitch
239- label = { i18n . translate ( 'xpack.ml.jobSelector.applyTimerangeSwitchLabel' , {
240- defaultMessage : 'Apply time range' ,
241- } ) }
242- checked = { applyTimeRange }
243- onChange = { toggleTimerangeSwitch }
244- data-test-subj = "mlFlyoutJobSelectorSwitchApplyTimeRange"
245- />
246- </ EuiFlexItem >
247- ) }
248289 </ EuiFlexGroup >
249- </ EuiFlexItem >
250- </ EuiFlexGroup >
251- < JobSelectorTable
252- jobs = { jobs }
253- ganttBarWidth = { ganttBarWidth }
254- groupsList = { groups }
255- onSelection = { handleNewSelection }
256- selectedIds = { newSelection }
257- singleSelection = { singleSelection }
258- timeseriesOnly = { timeseriesOnly }
259- />
260- </ EuiFlyoutBody >
261- < EuiFlyoutFooter >
262- < EuiFlexGroup >
263- < EuiFlexItem grow = { false } >
264- < EuiButton
265- onClick = { applySelection }
266- fill
267- isDisabled = { newSelection . length === 0 }
268- data-test-subj = "mlFlyoutJobSelectorButtonApply"
269- >
270- { i18n . translate ( 'xpack.ml.jobSelector.applyFlyoutButton' , {
271- defaultMessage : 'Apply' ,
272- } ) }
273- </ EuiButton >
274- </ EuiFlexItem >
275- < EuiFlexItem grow = { false } >
276- < EuiButtonEmpty
277- iconType = "cross"
278- onClick = { onFlyoutClose }
279- data-test-subj = "mlFlyoutJobSelectorButtonClose"
280- >
281- { i18n . translate ( 'xpack.ml.jobSelector.closeFlyoutButton' , {
282- defaultMessage : 'Close' ,
283- } ) }
284- </ EuiButtonEmpty >
285- </ EuiFlexItem >
290+ </ EuiFlyoutFooter >
286291 </ EuiFlexGroup >
287- </ EuiFlyoutFooter >
288- </ EuiFlyout >
292+ ) }
293+ </ EuiResizeObserver >
289294 ) ;
290295} ;
0 commit comments