@@ -20,15 +20,23 @@ import { withBusyState } from 'src/libs/utils';
2020import { WorkflowModal } from 'src/pages/workflows/workflow/common/WorkflowModal' ;
2121import { MethodDefinition } from 'src/pages/workflows/workflow-utils' ;
2222
23+ // Note: The first tab key in this array will determine the default tab selected
24+ // if the tab query parameter is not present or has an invalid value (and when
25+ // clicking on that tab, the tab query parameter will not be used in the URL)
26+ const tabKeys = [ 'mine' , 'public' ] as const ;
27+ type TabKey = ( typeof tabKeys ) [ number ] ; // 'mine' | 'public'
28+
29+ // Custom type guard
30+ const isTabKey = ( val : any ) : val is TabKey => _ . includes ( val , tabKeys ) ;
31+
32+ const defaultTabKey : TabKey = tabKeys [ 0 ] ;
33+
2334/**
2435 * Represents a list of method definitions grouped into two
25- * categories — My Workflows and Public Workflows — corresponding
36+ * categories — My Methods and Public Methods — corresponding
2637 * to the tabs above the workflows table.
2738 */
28- interface GroupedWorkflows {
29- mine : MethodDefinition [ ] ;
30- public : MethodDefinition [ ] ;
31- }
39+ type GroupedWorkflows = Record < TabKey , MethodDefinition [ ] > ;
3240
3341// This is based on the sort type from the FlexTable component
3442// When that component is converted to TypeScript, we should use its sort type
@@ -39,7 +47,7 @@ interface SortProperties {
3947}
4048
4149interface NewQueryParams {
42- newTab ?: string ;
50+ newTab ?: TabKey ;
4351 newFilter ?: string ;
4452}
4553
@@ -80,14 +88,16 @@ interface WorkflowListProps {
8088// TODO: consider wrapping query updates in useEffect
8189export const WorkflowList = ( props : WorkflowListProps ) => {
8290 const { queryParams = { } } = props ;
83- const { tab = 'mine' , filter = '' , ...query } = queryParams ;
91+ const { tab : queryTab , filter = '' , ...query } = queryParams ;
92+
93+ const selectedTab : TabKey = isTabKey ( queryTab ) ? queryTab : defaultTabKey ;
8494
8595 const signal : AbortSignal = useCancellation ( ) ;
8696 const [ busy , setBusy ] = useState < boolean > ( false ) ;
8797
8898 // workflows is undefined while the method definitions are still loading;
8999 // it is null if there is an error while loading
90- const [ workflows , setWorkflows ] = useState < GroupedWorkflows | null > ( ) ;
100+ const [ workflows , setWorkflows ] = useState < GroupedWorkflows | null | undefined > ( ) ;
91101
92102 // Valid direction values are 'asc' and 'desc' (based on expected
93103 // function signatures from the Sortable component used in this
@@ -99,9 +109,9 @@ export const WorkflowList = (props: WorkflowListProps) => {
99109 const [ pageNumber , setPageNumber ] = useState ( 1 ) ;
100110 const [ itemsPerPage , setItemsPerPage ] = useState ( 25 ) ;
101111
102- const getTabQueryName = ( newTab : string | undefined ) : string | undefined => ( newTab === 'mine' ? undefined : newTab ) ;
112+ const getTabQueryName = ( newTab : TabKey ) : TabKey | undefined => ( newTab === defaultTabKey ? undefined : newTab ) ;
103113
104- const getUpdatedQuery = ( { newTab = tab , newFilter = filter } : NewQueryParams ) : string => {
114+ const getUpdatedQuery = ( { newTab = selectedTab , newFilter = filter } : NewQueryParams ) : string => {
105115 // Note: setting undefined so that falsy values don't show up at all
106116 return qs . stringify (
107117 { ...query , tab : getTabQueryName ( newTab ) , filter : newFilter || undefined } ,
@@ -123,27 +133,30 @@ export const WorkflowList = (props: WorkflowListProps) => {
123133 setSort ( newSort ) ;
124134 } ;
125135
126- const tabName : string = tab || 'mine' ;
127- const tabs = { mine : 'My Workflows' , public : 'Public Workflows' } ;
136+ const tabNames : Record < TabKey , string > = { mine : 'My Methods' , public : 'Public Methods' } ;
128137
129- const getTabDisplayNames = ( workflows : GroupedWorkflows | null | undefined , currentTabName : string ) => {
130- const getCountString = ( tabName : keyof GroupedWorkflows ) : string => {
138+ const getTabDisplayNames = (
139+ workflows : GroupedWorkflows | null | undefined ,
140+ selectedTab : TabKey
141+ ) : Record < TabKey , string > => {
142+ const getCountString = ( tab : TabKey ) : string => {
131143 if ( workflows == null ) {
132144 return '' ;
133145 }
134146
135- // Only the current tab's workflow count reflects the search
147+ // Only the currently selected tab's workflow count reflects the search
136148 // filter (since the filter is cleared when switching tabs)
137- if ( tabName === currentTabName ) {
149+ if ( tab === selectedTab ) {
138150 return ` (${ sortedWorkflows . length } )` ;
139151 }
140- return ` (${ workflows [ tabName ] . length } )` ;
152+ return ` (${ workflows [ tab ] . length } )` ;
141153 } ;
142154
143- return {
144- mine : `My Workflows${ getCountString ( 'mine' ) } ` ,
145- public : `Public Workflows${ getCountString ( 'public' ) } ` ,
146- } ;
155+ const tabDisplayNames : Record < TabKey , string > = { ...tabNames } ; // (shallow) copy
156+ for ( const tabKey of tabKeys ) {
157+ tabDisplayNames [ tabKey ] += getCountString ( tabKey ) ;
158+ }
159+ return tabDisplayNames ;
147160 } ;
148161
149162 useOnMount ( ( ) => {
@@ -160,7 +173,7 @@ export const WorkflowList = (props: WorkflowListProps) => {
160173 } ) ;
161174 } catch ( error ) {
162175 setWorkflows ( null ) ;
163- notify ( 'error' , 'Error loading workflows ' , { detail : error instanceof Response ? await error . text ( ) : error } ) ;
176+ notify ( 'error' , 'Error loading methods ' , { detail : error instanceof Response ? await error . text ( ) : error } ) ;
164177 }
165178 } ) ;
166179
@@ -174,7 +187,7 @@ export const WorkflowList = (props: WorkflowListProps) => {
174187 snapshotId,
175188 } ) ;
176189
177- // Gets the sort key of a method definition based on the currently
190+ // Get the sort key of a method definition based on the currently
178191 // selected sort field such that numeric fields are sorted numerically
179192 // and other fields are sorted as case-insensitive strings
180193 const getSortKey = ( { [ sort . field ] : sortValue } : MethodDefinition ) : number | string => {
@@ -187,25 +200,30 @@ export const WorkflowList = (props: WorkflowListProps) => {
187200 return _ . lowerCase ( sortValue . toString ( ) ) ;
188201 } ;
189202
190- const sortedWorkflows : MethodDefinition [ ] = _ . flow < MethodDefinition [ ] , MethodDefinition [ ] , MethodDefinition [ ] > (
203+ const sortedWorkflows : MethodDefinition [ ] = _ . flow <
204+ // filter input type: MethodDefinition[] | undefined (extra [] are because the inputs are viewed as a rest parameter)
205+ ( MethodDefinition [ ] | undefined ) [ ] ,
206+ MethodDefinition [ ] , // filter output type / orderBy input type
207+ MethodDefinition [ ] // final result type
208+ > (
191209 _ . filter ( ( { namespace, name } : MethodDefinition ) => Utils . textMatch ( filter , `${ namespace } /${ name } ` ) ) ,
192210 _ . orderBy ( [ getSortKey ] , [ sort . direction ] )
193- ) ( workflows ?. [ tabName ] ) ;
211+ ) ( workflows ?. [ selectedTab ] ) ;
194212
195213 const firstPageIndex : number = ( pageNumber - 1 ) * itemsPerPage ;
196214 const lastPageIndex : number = firstPageIndex + itemsPerPage ;
197215 const paginatedWorkflows : MethodDefinition [ ] = sortedWorkflows . slice ( firstPageIndex , lastPageIndex ) ;
198216
199217 return (
200218 < FooterWrapper >
201- < TopBar title = 'Workflows ' href = '' >
219+ < TopBar title = 'Broad Methods Repository ' href = '' >
202220 { null /* no additional content to display in the top bar */ }
203221 </ TopBar >
204222 < TabBar
205- aria-label = 'workflows menu'
206- activeTab = { tabName }
207- tabNames = { Object . keys ( tabs ) }
208- displayNames = { getTabDisplayNames ( workflows , tabName ) }
223+ aria-label = 'methods list menu'
224+ activeTab = { selectedTab }
225+ tabNames = { tabKeys }
226+ displayNames = { getTabDisplayNames ( workflows , selectedTab ) }
209227 getHref = { ( currentTab ) => `${ Nav . getLink ( 'workflows' ) } ${ getUpdatedQuery ( { newTab : currentTab } ) } ` }
210228 getOnClick = { ( currentTab ) => ( e ) => {
211229 e . preventDefault ( ) ;
@@ -218,8 +236,8 @@ export const WorkflowList = (props: WorkflowListProps) => {
218236 < div style = { { display : 'flex' } } >
219237 < DelayedSearchInput
220238 style = { { width : 500 , display : 'flex' , justifyContent : 'flex-start' } }
221- placeholder = 'SEARCH WORKFLOWS '
222- aria-label = 'Search workflows '
239+ placeholder = 'SEARCH METHODS '
240+ aria-label = 'Search methods '
223241 onChange = { ( val ) => updateQuery ( { newFilter : val } ) }
224242 value = { filter }
225243 />
@@ -238,7 +256,7 @@ export const WorkflowList = (props: WorkflowListProps) => {
238256 < AutoSizer >
239257 { ( { width, height } ) => (
240258 < FlexTable
241- aria-label = { tabs [ tabName ] }
259+ aria-label = { tabNames [ selectedTab ] }
242260 width = { width }
243261 height = { height }
244262 sort = { sort as any /* necessary until FlexTable is converted to TS */ }
@@ -257,7 +275,7 @@ export const WorkflowList = (props: WorkflowListProps) => {
257275 // @ts -expect-error
258276 < Paginator
259277 filteredDataLength = { sortedWorkflows . length }
260- unfilteredDataLength = { workflows ! [ tabName ] . length }
278+ unfilteredDataLength = { workflows ! [ selectedTab ] . length }
261279 pageNumber = { pageNumber }
262280 setPageNumber = { setPageNumber }
263281 itemsPerPage = { itemsPerPage }
@@ -295,7 +313,7 @@ const getColumns = (
295313 field : 'name' ,
296314 headerRenderer : ( ) => (
297315 < WorkflowTableHeader sort = { sort } field = 'name' onSort = { onSort } >
298- Workflow
316+ Method
299317 </ WorkflowTableHeader >
300318 ) ,
301319 cellRenderer : ( { rowIndex } ) => {
@@ -359,8 +377,8 @@ const getColumns = (
359377export const navPaths = [
360378 {
361379 name : 'workflows' ,
362- path : '/workflows ' ,
380+ path : '/methods ' ,
363381 component : WorkflowList ,
364- title : 'Workflows ' ,
382+ title : 'Broad Methods Repository ' ,
365383 } ,
366384] ;
0 commit comments