1- import {
2- Checkbox ,
3- Table ,
4- TableBody ,
5- TableCell ,
6- TableContainer ,
7- TableHead ,
8- TableRow ,
9- } from "@material-ui/core" ;
101import _ from "lodash" ;
112import qs from "query-string" ;
123import * as React from "react" ;
@@ -24,31 +15,25 @@ import FilterDialog, {
2415} from "../FilterDialog" ;
2516import Flex from "../Flex" ;
2617import Icon , { IconType } from "../Icon" ;
27- import InfoModal from "../InfoModal" ;
2818import SearchField from "../SearchField" ;
29- import Spacer from "../Spacer" ;
30- import Text from "../Text" ;
3119import {
3220 filterRows ,
3321 filterSelectionsToQueryString ,
3422 filterText ,
3523 initialFormState ,
3624 parseFilterStateFromURL ,
37- sortByField ,
3825 toPairs ,
3926} from "./helpers" ;
40- import SortableLabel from "./SortableLabel" ;
27+
28+ import SearchedNamespacesModal from "./TableView/SearchedNamespacesModal" ;
29+ import TableView from "./TableView/TableView" ;
30+ import { SortField } from "./TableView/types" ;
4131import { Field , FilterState } from "./types" ;
4232
43- /** DataTable Properties */
4433export interface Props {
45- /** The ID of the table. */
4634 id ?: string ;
47- /** CSS MUI Overrides or other styling. */
4835 className ?: string ;
49- /** A list of objects with four fields: `label`, which is a string representing the column header, `value`, which can be a string, or a function that extracts the data needed to fill the table cell, and `sortValue`, which customizes your input to the search function */
5036 fields : Field [ ] ;
51- /** A list of data that will be iterated through to create the columns described in `fields`. */
5237 rows ?: any [ ] ;
5338 filters ?: FilterConfig ;
5439 dialogOpen ?: boolean ;
@@ -59,12 +44,6 @@ export interface Props {
5944 disableSort ?: boolean ;
6045 searchedNamespaces ?: SearchedNamespaces ;
6146}
62- //styled components
63- const EmptyRow = styled ( TableRow ) < { colSpan : number } > `
64- td {
65- text-align: center;
66- }
67- ` ;
6847
6948const TopBar = styled ( Flex ) `
7049 max-width: 100%;
@@ -75,7 +54,6 @@ const IconFlex = styled(Flex)`
7554 padding: 0 ${ ( props ) => props . theme . spacing . small } ;
7655` ;
7756
78- /** Form DataTable */
7957function UnstyledDataTable ( {
8058 id,
8159 className,
@@ -90,21 +68,31 @@ function UnstyledDataTable({
9068 disableSort,
9169 searchedNamespaces,
9270} : Props ) {
93- //URL info
9471 const history = useHistory ( ) ;
9572 const location = useLocation ( ) ;
9673 const search = location . search ;
9774 const state = parseFilterStateFromURL ( search ) ;
98-
9975 const [ filterDialogOpen , setFilterDialogOpen ] = React . useState ( dialogOpen ) ;
100- const [ searchedNamespacesModalOpen , setSearchedNamespacesModalOpen ] =
101- React . useState ( false ) ;
76+
77+ const [ checked , setChecked ] = React . useState ( [ ] ) ;
78+
10279 const [ filterState , setFilterState ] = React . useState < FilterState > ( {
10380 filters : selectionsToFilters ( state . initialSelections , filters ) ,
10481 formState : initialFormState ( filters , state . initialSelections ) ,
10582 textFilters : state . textFilters ,
10683 } ) ;
10784
85+ const [ sortedItem , setSortedItem ] = React . useState < SortField | null > ( ( ) => {
86+ const defaultSortField = fields . find ( ( f ) => f . defaultSort ) ;
87+ const sortField = defaultSortField
88+ ? {
89+ ...defaultSortField ,
90+ reverseSort : false ,
91+ }
92+ : null ;
93+ return sortField ;
94+ } ) ;
95+
10896 const handleFilterChange = ( sel : FilterSelections ) => {
10997 const filterQuery = filterSelectionsToQueryString ( sel ) ;
11098 history . replace ( { ...location , search : filterQuery } ) ;
@@ -114,6 +102,20 @@ function UnstyledDataTable({
114102 filtered = filterText ( filtered , fields , filterState . textFilters ) ;
115103 const chips = toPairs ( filterState ) ;
116104
105+ const sortItems = ( filtered ) => {
106+ let sorted = filtered ;
107+ if ( sortedItem ) {
108+ sorted = _ . orderBy (
109+ filtered ,
110+ [ sortedItem . sortValue || sortedItem . value ] ,
111+ [ sortedItem . reverseSort ? "desc" : "asc" ]
112+ ) ;
113+ }
114+ return sorted ;
115+ } ;
116+
117+ const items = sortItems ( filtered ) ;
118+
117119 const doChange = ( formState ) => {
118120 if ( handleFilterChange ) {
119121 handleFilterChange ( formState ) ;
@@ -176,95 +178,8 @@ function UnstyledDataTable({
176178 setFilterState ( { ...filterState , filters, formState } ) ;
177179 } ;
178180
179- const [ sortFieldIndex , setSortFieldIndex ] = React . useState ( ( ) => {
180- let sortFieldIndex = fields . findIndex ( ( f ) => f . defaultSort ) ;
181-
182- if ( sortFieldIndex === - 1 ) {
183- sortFieldIndex = 0 ;
184- }
185-
186- return sortFieldIndex ;
187- } ) ;
188-
189- const secondarySortFieldIndex = fields . findIndex ( ( f ) => f . secondarySort ) ;
190-
191- const [ reverseSort , setReverseSort ] = React . useState ( false ) ;
192-
193- let sortFields = [ fields [ sortFieldIndex ] ] ;
194-
195- const useSecondarySort =
196- secondarySortFieldIndex > - 1 && sortFieldIndex != secondarySortFieldIndex ;
197-
198- if ( useSecondarySort ) {
199- sortFields = sortFields . concat ( fields [ secondarySortFieldIndex ] ) ;
200- sortFields = sortFields . concat (
201- fields . filter (
202- ( _ , index ) =>
203- index != sortFieldIndex && index != secondarySortFieldIndex
204- )
205- ) ;
206- } else {
207- sortFields = sortFields . concat (
208- fields . filter ( ( _ , index ) => index != sortFieldIndex )
209- ) ;
210- }
211-
212- const sorted = sortByField (
213- filtered ,
214- reverseSort ,
215- sortFields ,
216- useSecondarySort ,
217- disableSort
218- ) ;
219-
220- const numFields = fields . length + ( checkboxes ? 1 : 0 ) ;
221-
222- const [ checked , setChecked ] = React . useState ( [ ] ) ;
223-
224- const r = _ . map ( sorted , ( r , i ) => {
225- return (
226- < TableRow key = { r . uid || i } >
227- { checkboxes && (
228- < TableCell style = { { padding : "0px" } } >
229- < Checkbox
230- checked = { _ . includes ( checked , r . uid ) }
231- onChange = { ( e ) => {
232- if ( e . target . checked ) setChecked ( [ ...checked , r . uid ] ) ;
233- else setChecked ( _ . without ( checked , r . uid ) ) ;
234- } }
235- color = "primary"
236- />
237- </ TableCell >
238- ) }
239- { _ . map ( fields , ( f ) => {
240- const style : React . CSSProperties = {
241- ...( f . minWidth && { minWidth : f . minWidth } ) ,
242- ...( f . maxWidth && { maxWidth : f . maxWidth } ) ,
243- } ;
244-
245- return (
246- < TableCell
247- style = { Object . keys ( style ) . length > 0 ? style : undefined }
248- key = { f . label }
249- >
250- < Text >
251- { ( typeof f . value === "function" ? f . value ( r ) : r [ f . value ] ) ||
252- "-" }
253- </ Text >
254- </ TableCell >
255- ) ;
256- } ) }
257- </ TableRow >
258- ) ;
259- } ) ;
260-
261181 return (
262182 < Flex wide tall column className = { className } >
263- < InfoModal
264- searchedNamespaces = { searchedNamespaces }
265- open = { searchedNamespacesModalOpen }
266- onCloseModal = { setSearchedNamespacesModalOpen }
267- />
268183 < TopBar wide align end >
269184 { checkboxes && < CheckboxActions checked = { checked } rows = { filtered } /> }
270185 { filters && ! hideSearchAndFilters && (
@@ -276,18 +191,9 @@ function UnstyledDataTable({
276191 />
277192 < IconFlex align >
278193 { searchedNamespaces && (
279- < IconButton
280- onClick = { ( ) =>
281- setSearchedNamespacesModalOpen ( ! searchedNamespacesModalOpen )
282- }
283- variant = "text"
284- >
285- < Icon
286- type = { IconType . InfoIcon }
287- size = "medium"
288- color = "neutral20"
289- />
290- </ IconButton >
194+ < SearchedNamespacesModal
195+ searchedNamespaces = { searchedNamespaces }
196+ />
291197 ) }
292198 < SearchField onSubmit = { handleTextSearchSubmit } />
293199 < IconButton
@@ -306,76 +212,21 @@ function UnstyledDataTable({
306212 ) }
307213 </ TopBar >
308214 < Flex wide tall >
309- < TableContainer id = { id } >
310- < Table aria-label = "simple table" >
311- < TableHead >
312- < TableRow >
313- { checkboxes && (
314- < TableCell key = { "checkboxes" } >
315- < Checkbox
316- checked = { filtered ?. length === checked . length }
317- onChange = { ( e ) =>
318- e . target . checked
319- ? setChecked ( filtered ?. map ( ( r ) => r . uid ) )
320- : setChecked ( [ ] )
321- }
322- color = "primary"
323- />
324- </ TableCell >
325- ) }
326- { _ . map ( fields , ( f , index ) => (
327- < TableCell key = { f . label } >
328- { typeof f . labelRenderer === "function" ? (
329- f . labelRenderer ( r )
330- ) : (
331- < SortableLabel
332- fields = { fields }
333- fieldIndex = { index }
334- sortFieldIndex = { sortFieldIndex }
335- reverseSort = { reverseSort }
336- setSortFieldIndex = { ( ...args ) => {
337- if ( onColumnHeaderClick ) {
338- onColumnHeaderClick ( f ) ;
339- }
340-
341- setSortFieldIndex ( ...args ) ;
342- } }
343- setReverseSort = { ( isReverse ) => {
344- if ( onColumnHeaderClick ) {
345- onColumnHeaderClick ( f ) ;
346- }
347-
348- setReverseSort ( isReverse ) ;
349- } }
350- />
351- ) }
352- </ TableCell >
353- ) ) }
354- </ TableRow >
355- </ TableHead >
356- < TableBody >
357- { r . length > 0 ? (
358- r
359- ) : (
360- < EmptyRow colSpan = { numFields } >
361- < TableCell colSpan = { numFields } >
362- < Flex center align >
363- < Icon
364- color = "neutral20"
365- type = { IconType . RemoveCircleIcon }
366- size = "base"
367- />
368- < Spacer padding = "xxs" />
369- { emptyMessagePlaceholder || (
370- < Text color = "neutral30" > No data</ Text >
371- ) }
372- </ Flex >
373- </ TableCell >
374- </ EmptyRow >
375- ) }
376- </ TableBody >
377- </ Table >
378- </ TableContainer >
215+ < TableView
216+ fields = { fields }
217+ rows = { items }
218+ defaultSortedField = { sortedItem }
219+ id = { id }
220+ hasCheckboxes = { checkboxes }
221+ emptyMessagePlaceholder = { emptyMessagePlaceholder }
222+ checkedFields = { checked }
223+ disableSort = { disableSort }
224+ onBatchCheck = { ( checked ) => setChecked ( checked ) }
225+ onSortChange = { ( field ) => {
226+ if ( onColumnHeaderClick ) onColumnHeaderClick ( field ) ;
227+ setSortedItem ( field ) ;
228+ } }
229+ />
379230 { ! hideSearchAndFilters && (
380231 < FilterDialog
381232 onFilterSelect = { handleFilterSelect }
0 commit comments