44 * you may not use this file except in compliance with the Elastic License.
55 */
66
7- import React , { MouseEventHandler , FC , useContext , useState } from 'react' ;
7+ import React , { MouseEventHandler , FC , useContext , useEffect , useState } from 'react' ;
88
99import { i18n } from '@kbn/i18n' ;
1010
1111import {
12- Direction ,
13- EuiBadge ,
12+ EuiBasicTable ,
13+ EuiBasicTableProps ,
1414 EuiButtonEmpty ,
1515 EuiButtonIcon ,
1616 EuiCallOut ,
1717 EuiEmptyPrompt ,
1818 EuiFlexGroup ,
1919 EuiFlexItem ,
20- EuiInMemoryTable ,
21- EuiSearchBarProps ,
20+ EuiSearchBar ,
21+ EuiSpacer ,
2222 EuiPopover ,
2323 EuiTitle ,
2424} from '@elastic/eui' ;
2525
26- import { TransformId , TRANSFORM_STATE } from '../../../../../../common' ;
26+ import { TransformId } from '../../../../../../common' ;
2727
2828import {
2929 useRefreshTransformList ,
3030 TransformListRow ,
31- TRANSFORM_MODE ,
3231 TRANSFORM_LIST_COLUMN ,
3332} from '../../../../common' ;
3433import { useStopTransforms } from '../../../../hooks' ;
@@ -45,9 +44,11 @@ import {
4544import { useStartAction , StartActionName , StartActionModal } from '../action_start' ;
4645import { StopActionName } from '../action_stop' ;
4746
48- import { ItemIdToExpandedRowMap , Clause , TermClause , FieldClause , Value } from './common' ;
49- import { getTaskStateBadge , useColumns } from './use_columns' ;
47+ import { ItemIdToExpandedRowMap } from './common' ;
48+ import { useColumns } from './use_columns' ;
5049import { ExpandedRow } from './expanded_row' ;
50+ import { TransformSearchBar , filterTransforms } from './transform_search_bar' ;
51+ import { useTableSettings } from './use_table_settings' ;
5152
5253function getItemIdToExpandedRowMap (
5354 itemIds : TransformId [ ] ,
@@ -62,14 +63,6 @@ function getItemIdToExpandedRowMap(
6263 } , { } as ItemIdToExpandedRowMap ) ;
6364}
6465
65- function stringMatch ( str : string | undefined , substr : any ) {
66- return (
67- typeof str === 'string' &&
68- typeof substr === 'string' &&
69- ( str . toLowerCase ( ) . match ( substr . toLowerCase ( ) ) === null ) === false
70- ) ;
71- }
72-
7366interface Props {
7467 errorMessage : any ;
7568 isInitialized : boolean ;
@@ -88,24 +81,20 @@ export const TransformList: FC<Props> = ({
8881 const [ isLoading , setIsLoading ] = useState ( false ) ;
8982 const { refresh } = useRefreshTransformList ( { isLoading : setIsLoading } ) ;
9083
91- const [ filterActive , setFilterActive ] = useState ( false ) ;
92-
93- const [ filteredTransforms , setFilteredTransforms ] = useState < TransformListRow [ ] > ( [ ] ) ;
84+ const [ searchQueryText , setSearchQueryText ] = useState < string > ( '' ) ;
85+ const [ filteredTransforms , setFilteredTransforms ] = useState < {
86+ active : boolean ;
87+ items : TransformListRow [ ] ;
88+ } > ( {
89+ active : false ,
90+ items : [ ] ,
91+ } ) ;
9492 const [ expandedRowItemIds , setExpandedRowItemIds ] = useState < TransformId [ ] > ( [ ] ) ;
95-
9693 const [ transformSelection , setTransformSelection ] = useState < TransformListRow [ ] > ( [ ] ) ;
9794 const [ isActionsMenuOpen , setIsActionsMenuOpen ] = useState ( false ) ;
9895 const bulkStartAction = useStartAction ( false ) ;
9996 const bulkDeleteAction = useDeleteAction ( false ) ;
10097
101- const [ searchError , setSearchError ] = useState < any > ( undefined ) ;
102-
103- const [ pageIndex , setPageIndex ] = useState ( 0 ) ;
104- const [ pageSize , setPageSize ] = useState ( 10 ) ;
105-
106- const [ sortField , setSortField ] = useState < string > ( TRANSFORM_LIST_COLUMN . ID ) ;
107- const [ sortDirection , setSortDirection ] = useState < Direction > ( 'asc' ) ;
108-
10998 const stopTransforms = useStopTransforms ( ) ;
11099
111100 const { capabilities } = useContext ( AuthorizationContext ) ;
@@ -114,90 +103,41 @@ export const TransformList: FC<Props> = ({
114103 ! capabilities . canPreviewTransform ||
115104 ! capabilities . canStartStopTransform ;
116105
117- const onQueryChange = ( {
118- query,
119- error,
120- } : Parameters < NonNullable < EuiSearchBarProps [ 'onChange' ] > > [ 0 ] ) => {
121- if ( error ) {
122- setSearchError ( error . message ) ;
106+ const { columns, modals : singleActionModals } = useColumns (
107+ expandedRowItemIds ,
108+ setExpandedRowItemIds ,
109+ transformSelection
110+ ) ;
111+
112+ const setQueryClauses = ( queryClauses : any ) => {
113+ if ( queryClauses . length ) {
114+ const filtered = filterTransforms ( transforms , queryClauses ) ;
115+ setFilteredTransforms ( { active : true , items : filtered } ) ;
123116 } else {
124- let clauses : Clause [ ] = [ ] ;
125- if ( query && query . ast !== undefined && query . ast . clauses !== undefined ) {
126- clauses = query . ast . clauses ;
127- }
128- if ( clauses . length > 0 ) {
129- setFilterActive ( true ) ;
130- filterTransforms ( clauses as Array < TermClause | FieldClause > ) ;
131- } else {
132- setFilterActive ( false ) ;
133- }
134- setSearchError ( undefined ) ;
117+ setFilteredTransforms ( { active : false , items : [ ] } ) ;
135118 }
136119 } ;
137120
138- const filterTransforms = ( clauses : Array < TermClause | FieldClause > ) => {
139- setIsLoading ( true ) ;
140- // keep count of the number of matches we make as we're looping over the clauses
141- // we only want to return transforms which match all clauses, i.e. each search term is ANDed
142- // { transform-one: { transform: { id: transform-one, config: {}, state: {}, ... }, count: 0 }, transform-two: {...} }
143- const matches : Record < string , any > = transforms . reduce ( ( p : Record < string , any > , c ) => {
144- p [ c . id ] = {
145- transform : c ,
146- count : 0 ,
147- } ;
148- return p ;
149- } , { } ) ;
150-
151- clauses . forEach ( ( c ) => {
152- // the search term could be negated with a minus, e.g. -bananas
153- const bool = c . match === 'must' ;
154- let ts = [ ] ;
155-
156- if ( c . type === 'term' ) {
157- // filter term based clauses, e.g. bananas
158- // match on ID and description
159- // if the term has been negated, AND the matches
160- if ( bool === true ) {
161- ts = transforms . filter (
162- ( transform ) =>
163- stringMatch ( transform . id , c . value ) === bool ||
164- stringMatch ( transform . config . description , c . value ) === bool
165- ) ;
166- } else {
167- ts = transforms . filter (
168- ( transform ) =>
169- stringMatch ( transform . id , c . value ) === bool &&
170- stringMatch ( transform . config . description , c . value ) === bool
171- ) ;
121+ useEffect ( ( ) => {
122+ const filterList = ( ) => {
123+ if ( searchQueryText !== '' ) {
124+ const query = EuiSearchBar . Query . parse ( searchQueryText ) ;
125+ let clauses : any = [ ] ;
126+ if ( query && query . ast !== undefined && query . ast . clauses !== undefined ) {
127+ clauses = query . ast . clauses ;
172128 }
129+ setQueryClauses ( clauses ) ;
173130 } else {
174- // filter other clauses, i.e. the mode and status filters
175- if ( Array . isArray ( c . value ) ) {
176- // the status value is an array of string(s) e.g. ['failed', 'stopped']
177- ts = transforms . filter ( ( transform ) =>
178- ( c . value as Value [ ] ) . includes ( transform . stats . state )
179- ) ;
180- } else {
181- ts = transforms . filter ( ( transform ) => transform . mode === c . value ) ;
182- }
131+ setQueryClauses ( [ ] ) ;
183132 }
184-
185- ts . forEach ( ( t ) => matches [ t . id ] . count ++ ) ;
186- } ) ;
187-
188- // loop through the matches and return only transforms which have match all the clauses
189- const filtered = Object . values ( matches )
190- . filter ( ( m ) => ( m && m . count ) >= clauses . length )
191- . map ( ( m ) => m . transform ) ;
192-
193- setFilteredTransforms ( filtered ) ;
194- setIsLoading ( false ) ;
195- } ;
196-
197- const { columns, modals : singleActionModals } = useColumns (
198- expandedRowItemIds ,
199- setExpandedRowItemIds ,
200- transformSelection
133+ } ;
134+ filterList ( ) ;
135+ // eslint-disable-next-line
136+ } , [ searchQueryText , transforms ] ) ; // missing dependency setQueryClauses
137+
138+ const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings (
139+ TRANSFORM_LIST_COLUMN . ID ,
140+ filteredTransforms . active ? filteredTransforms . items : transforms
201141 ) ;
202142
203143 // Before the transforms have been loaded for the first time, display the loading indicator only.
@@ -246,23 +186,8 @@ export const TransformList: FC<Props> = ({
246186 ) ;
247187 }
248188
249- const sorting = {
250- sort : {
251- field : sortField ,
252- direction : sortDirection ,
253- } ,
254- } ;
255-
256189 const itemIdToExpandedRowMap = getItemIdToExpandedRowMap ( expandedRowItemIds , transforms ) ;
257190
258- const pagination = {
259- initialPageIndex : pageIndex ,
260- initialPageSize : pageSize ,
261- totalItemCount : transforms . length ,
262- pageSizeOptions : [ 10 , 20 , 50 ] ,
263- hidePerPageOptions : false ,
264- } ;
265-
266191 const bulkActionMenuItems = [
267192 < div key = "startAction" className = "transform__BulkActionItem" >
268193 < EuiButtonEmpty onClick = { ( ) => bulkStartAction . openModal ( transformSelection ) } >
@@ -331,7 +256,7 @@ export const TransformList: FC<Props> = ({
331256 ] ;
332257 } ;
333258
334- const renderToolsRight = ( ) => (
259+ const toolsRight = (
335260 < EuiFlexGroup gutterSize = "m" justifyContent = "spaceAround" >
336261 < EuiFlexItem >
337262 < RefreshTransformListButton onClick = { refresh } isLoading = { isLoading } />
@@ -342,56 +267,6 @@ export const TransformList: FC<Props> = ({
342267 </ EuiFlexGroup >
343268 ) ;
344269
345- const search = {
346- toolsLeft : transformSelection . length > 0 ? renderToolsLeft ( ) : undefined ,
347- toolsRight : renderToolsRight ( ) ,
348- onChange : onQueryChange ,
349- box : {
350- incremental : true ,
351- } ,
352- filters : [
353- {
354- type : 'field_value_selection' as const ,
355- field : 'state.state' ,
356- name : i18n . translate ( 'xpack.transform.statusFilter' , { defaultMessage : 'Status' } ) ,
357- multiSelect : 'or' as const ,
358- options : Object . values ( TRANSFORM_STATE ) . map ( ( val ) => ( {
359- value : val ,
360- name : val ,
361- view : getTaskStateBadge ( val ) ,
362- } ) ) ,
363- } ,
364- {
365- type : 'field_value_selection' as const ,
366- field : 'mode' ,
367- name : i18n . translate ( 'xpack.transform.modeFilter' , { defaultMessage : 'Mode' } ) ,
368- multiSelect : false ,
369- options : Object . values ( TRANSFORM_MODE ) . map ( ( val ) => ( {
370- value : val ,
371- name : val ,
372- view : (
373- < EuiBadge className = "transform__TaskModeBadge" color = "hollow" >
374- { val }
375- </ EuiBadge >
376- ) ,
377- } ) ) ,
378- } ,
379- ] ,
380- } ;
381-
382- const onTableChange = ( {
383- page = { index : 0 , size : 10 } ,
384- sort = { field : TRANSFORM_LIST_COLUMN . ID as string , direction : 'asc' } ,
385- } ) => {
386- const { index, size } = page ;
387- setPageIndex ( index ) ;
388- setPageSize ( size ) ;
389-
390- const { field, direction } = sort ;
391- setSortField ( field as string ) ;
392- setSortDirection ( direction as Direction ) ;
393- } ;
394-
395270 const selection = {
396271 onSelectionChange : ( selected : TransformListRow [ ] ) => setTransformSelection ( selected ) ,
397272 } ;
@@ -404,30 +279,38 @@ export const TransformList: FC<Props> = ({
404279
405280 { /* Single Action Modals */ }
406281 { singleActionModals }
407-
408- < EuiInMemoryTable
409- allowNeutralSort = { false }
410- className = "transform__TransformTable"
282+ < EuiFlexGroup alignItems = "center" >
283+ { transformSelection . length > 0 ? (
284+ < EuiFlexItem grow = { false } > { renderToolsLeft ( ) } </ EuiFlexItem >
285+ ) : null }
286+ < EuiFlexItem >
287+ < TransformSearchBar
288+ searchQueryText = { searchQueryText }
289+ setSearchQueryText = { setSearchQueryText }
290+ />
291+ </ EuiFlexItem >
292+ < EuiFlexItem grow = { false } > { toolsRight } </ EuiFlexItem >
293+ </ EuiFlexGroup >
294+ < EuiSpacer size = "l" />
295+ < EuiBasicTable < TransformListRow >
411296 columns = { columns }
412- error = { searchError }
413297 hasActions = { false }
414298 isExpandable = { true }
415299 isSelectable = { false }
416- items = { filterActive ? filteredTransforms : transforms }
300+ items = { pageOfItems as TransformListRow [ ] }
417301 itemId = { TRANSFORM_LIST_COLUMN . ID }
418302 itemIdToExpandedRowMap = { itemIdToExpandedRowMap }
419303 loading = { isLoading || transformsLoading }
420- onTableChange = { onTableChange }
421- pagination = { pagination }
422- rowProps = { ( item ) => ( {
423- 'data-test-subj' : `transformListRow row-${ item . id } ` ,
424- } ) }
304+ onChange = { onTableChange as EuiBasicTableProps < TransformListRow > [ 'onChange' ] }
425305 selection = { selection }
306+ pagination = { pagination ! }
426307 sorting = { sorting }
427- search = { search }
428308 data-test-subj = { `transformListTable ${
429309 isLoading || transformsLoading ? 'loading' : 'loaded'
430310 } `}
311+ rowProps = { ( item ) => ( {
312+ 'data-test-subj' : `transformListRow row-${ item . id } ` ,
313+ } ) }
431314 />
432315 </ div >
433316 ) ;
0 commit comments