@@ -5,6 +5,7 @@ import { useMemo, useState } from "react";
55import { MultiSelect , ItemRenderer , ItemPredicate } from "@blueprintjs/select" ;
66import { MenuItem , Spinner , InputGroup } from "@blueprintjs/core" ;
77import styles from "./postgrest.module.sass" ;
8+ import { ExpansionPanel } from "@macrostrat/map-interface" ;
89
910const h = hyper . styled ( styles ) ;
1011
@@ -32,6 +33,8 @@ interface PostgRESTInfiniteScrollProps extends InfiniteScrollProps<any> {
3233 tagInputProps : any ;
3334 popoverProps : any ;
3435 } > ;
36+ group_key ?: string ;
37+ groups ?: Array < { value : string ; label : string } > ;
3538}
3639
3740export function PostgRESTInfiniteScrollView (
@@ -54,6 +57,7 @@ export function PostgRESTInfiniteScrollView(
5457 key,
5558 toggles = null ,
5659 searchColumns = undefined ,
60+ group_key = undefined ,
5761 ...rest
5862 } = props ;
5963
@@ -236,35 +240,50 @@ export function PostgRESTInfiniteScrollView(
236240 h ( SearchBarToUse , {
237241 onChange : ( value ) => setFilterValue ( value || "" ) ,
238242 } ) ,
239- h ( MultiSelectToUse , {
240- items : keys . filter ( ( item ) => ! selectedItems . includes ( item . value ) ) ,
241- itemRenderer ,
242- itemPredicate : filterItem ,
243- selectedItems ,
244- onItemSelect : handleSelect ,
245- tagRenderer : ( value ) => {
246- const found = keys . find ( ( k ) => k . value === value ) ;
247- return found ? found . label : value ;
248- } ,
249- onRemove : handleRemove ,
250- tagInputProps : {
243+ h . if ( searchColumns == null || searchColumns . length > 1 ) (
244+ MultiSelectToUse ,
245+ {
246+ items : keys . filter ( ( item ) => ! selectedItems . includes ( item . value ) ) ,
247+ itemRenderer ,
248+ itemPredicate : filterItem ,
249+ selectedItems ,
250+ onItemSelect : handleSelect ,
251+ tagRenderer : ( value ) => {
252+ const found = keys . find ( ( k ) => k . value === value ) ;
253+ return found ? found . label : value ;
254+ } ,
251255 onRemove : handleRemove ,
252- placeholder : "Select a column(s) to filter by..." ,
256+ tagInputProps : {
257+ onRemove : handleRemove ,
258+ placeholder : "Select a column(s) to filter by..." ,
259+ } ,
260+ popoverProps : { minimal : true } ,
253261 } ,
254- popoverProps : { minimal : true } ,
255- } ) ,
262+ ) ,
256263 ] ) ,
257264 h . if ( toggles ) ( "div.toggles" , toggles ) ,
258265 ] ) ,
259- h ( InfiniteScrollView , {
260- ...rest ,
261- route,
262- getNextParams : getNextParams ?? defaultGetNextParams ,
263- params : params ?? defaultParams ,
264- initialItems : newInitialItems ,
265- hasMore : hasMore ?? defaultHasMore ,
266- key : newKey ,
267- } ) ,
266+ group_key
267+ ? Grouping ( {
268+ group_key,
269+ groups : props . groups ?? [ ] ,
270+ route,
271+ id_key,
272+ params : defaultParams ,
273+ getNextParams : getNextParams ?? defaultGetNextParams ,
274+ hasMore : hasMore ?? defaultHasMore ,
275+ key : newKey ,
276+ rest,
277+ } )
278+ : h ( InfiniteScrollView , {
279+ ...rest ,
280+ route,
281+ getNextParams : getNextParams ?? defaultGetNextParams ,
282+ params : params ?? defaultParams ,
283+ initialItems : newInitialItems ,
284+ hasMore : hasMore ?? defaultHasMore ,
285+ key : newKey ,
286+ } ) ,
268287 ] ) ;
269288}
270289
@@ -282,3 +301,80 @@ function SearchBar({ onChange, placeholder = "Search..." }) {
282301 leftIcon : "search" ,
283302 } ) ;
284303}
304+
305+ interface GroupingProps {
306+ group_key : string ;
307+ groups : Array < { value : string ; label : string } > ;
308+ route : string ;
309+ id_key : string ;
310+ params ?: Record < string , any > ;
311+ getNextParams ?: (
312+ response : any [ ] ,
313+ params : Record < string , any > ,
314+ ) => Record < string , any > ;
315+ hasMore ?: ( response : any [ ] ) => boolean ;
316+ key ?: string ;
317+ rest ?: any ;
318+ }
319+
320+ function Grouping ( props : GroupingProps ) {
321+ const {
322+ group_key,
323+ groups,
324+ route,
325+ id_key,
326+ params,
327+ getNextParams,
328+ hasMore,
329+ rest,
330+ } = props ;
331+
332+ return h ( "div.group-page" , [
333+ groups . map ( ( group ) => {
334+ if ( ! group . value || ! group . label ) {
335+ throw new Error ( "Each group must have a value and label" ) ;
336+ }
337+
338+ return h ( GroupPanel , {
339+ group,
340+ route,
341+ id_key,
342+ params : {
343+ ...params ,
344+ [ group_key ] : "eq." + group . value ,
345+ } ,
346+ getNextParams,
347+ hasMore,
348+ ...rest ,
349+ } ) ;
350+ } ) ,
351+ ] ) ;
352+ }
353+
354+ function GroupPanel ( props ) {
355+ const { group, route, params, getNextParams, hasMore, key, ...rest } = props ;
356+
357+ const data = useAPIResult ( route , {
358+ ...params ,
359+ limit : 1 ,
360+ } ) ;
361+
362+ if ( ! data || data ?. length === 0 ) return null ;
363+
364+ return h (
365+ ExpansionPanel ,
366+ {
367+ title : group . label ,
368+ } ,
369+ [
370+ h ( InfiniteScrollView , {
371+ key : key || group . value ,
372+ route,
373+ params,
374+ getNextParams,
375+ hasMore,
376+ ...rest ,
377+ } ) ,
378+ ] ,
379+ ) ;
380+ }
0 commit comments