Skip to content

Commit 344b754

Browse files
committed
OpenConceptLab/ocl_issues#2183 | Added filters in search
1 parent 3c4fbcd commit 344b754

3 files changed

Lines changed: 85 additions & 19 deletions

File tree

src/components/map-projects/MapProject.jsx

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ const MapProject = () => {
127127
const [matchedConcepts, setMatchedConcepts] = React.useState([]);
128128
const [otherMatchedConcepts, setOtherMatchedConcepts] = React.useState([]);
129129
const [searchedConcepts, setSearchedConcepts] = React.useState({});
130+
const [facets, setFacets] = React.useState({});
131+
const [appliedFacets, setAppliedFacets] = React.useState({});
130132
const [searchResponse, setSearchResponse] = React.useState({});
131133
const [algo, setAlgo] = React.useState('llm')
132134
const [notes, setNotes] = React.useState({})
@@ -397,6 +399,7 @@ const MapProject = () => {
397399
setMatchedConcepts([])
398400
setOtherMatchedConcepts([])
399401
setSearchedConcepts({})
402+
setFacets({})
400403
setSearchResponse({})
401404
setNotes({})
402405
setMapTypes({})
@@ -873,7 +876,7 @@ const MapProject = () => {
873876
.overrideURL(url)
874877
.get(null, null, {includeMappings: true, mappingBrief: true, mapTypes: 'SAME-AS,SAME AS,SAME_AS', verbose: true})
875878
.then(response => {
876-
const res = {...response.data, search_meta: {...matched.search_meta}, repo: {...matched.repo}}
879+
const res = {...response?.data, search_meta: {...matched.search_meta}, repo: {...matched.repo}}
877880
setConceptCache({...conceptCache, [url]: res})
878881
})
879882
setRow(csvRow)
@@ -966,6 +969,8 @@ const MapProject = () => {
966969
if(newValue === 'candidates' && repo?.id && !find(otherMatchedConcepts, c => c.row.__index === rowIndex)?.results?.length) {
967970
fetchOtherCandidates()
968971
}
972+
if(newValue === 'search' && isEmpty(facets[rowIndex]))
973+
getFacets()
969974
}
970975

971976
const onDecisionChange = (event, newValue) => {
@@ -1034,11 +1039,11 @@ const MapProject = () => {
10341039
semantic: algo === 'llm'
10351040
}).then(response => {
10361041
if(offset === 0)
1037-
setOtherMatchedConcepts([...reject(otherMatchedConcepts, c => c.row.__index == __row.__index), ...response.data])
1042+
setOtherMatchedConcepts([...reject(otherMatchedConcepts, c => c.row.__index == __row.__index), ...(response?.data || [])])
10381043
else {
10391044
const newMatches = [...otherMatchedConcepts]
10401045
const index = findIndex(newMatches, match => match.row.__index === __row.__index)
1041-
newMatches[index].results = [...newMatches[index].results, ...(response.data[0].results || [])]
1046+
newMatches[index].results = [...newMatches[index].results, ...(response?.data[0]?.results || [])]
10421047
setOtherMatchedConcepts(newMatches)
10431048
}
10441049
setIsLoadingInDecisionView(false)
@@ -1057,7 +1062,7 @@ const MapProject = () => {
10571062
fetchOtherCandidates(null, currentResults)
10581063
}
10591064

1060-
const searchCandidates = (event, page, pageSize, includeRetired) => {
1065+
const searchCandidates = (event, page, pageSize, includeRetired, appliedFilters) => {
10611066
setIsLoadingInDecisionView(true)
10621067
APIService.new().overrideURL(repoVersion.version_url).appendToUrl('concepts/').get(null, null, {
10631068
includeSearchMeta: true,
@@ -1068,17 +1073,44 @@ const MapProject = () => {
10681073
limit: pageSize || 5,
10691074
q: searchStr,
10701075
page: page || 1,
1071-
includeRetired: includeRetired === undefined ? retired : includeRetired
1076+
includeRetired: includeRetired === undefined ? retired : includeRetired,
1077+
...getFacetQueryParam(appliedFilters || appliedFacets[rowIndex])
10721078
}).then(response => {
10731079
let items = response.data
10741080
setSearchedConcepts({...searchedConcepts, [row.__index]: items})
10751081
setSearchResponse(response)
10761082
setIsLoadingInDecisionView(false)
1083+
if(!page || page == 1)
1084+
getFacets()
10771085
if(items.length > 0)
10781086
setTimeout(() => highlightTexts(items, null, false), 100)
10791087
});
10801088
}
10811089

1090+
const getFacets = () => {
1091+
APIService.new().overrideURL(repoVersion.version_url).appendToUrl('concepts/').get(null, null, {
1092+
q: searchStr,
1093+
includeRetired: retired,
1094+
facetsOnly: true
1095+
}).then(response => {
1096+
setFacets({...facets, [row.__index]: response?.data?.facets?.fields || {}})
1097+
})
1098+
}
1099+
1100+
const getFacetQueryParam = filters => {
1101+
const queryParam = {}
1102+
forEach(
1103+
filters, (value, field) => {
1104+
queryParam[field] = keys(pickBy(value, Boolean)).join(',')
1105+
}
1106+
)
1107+
1108+
if(queryParam?.retired === 'true,false' || queryParam?.retired === 'false,true')
1109+
queryParam['includeRetired'] = true
1110+
1111+
return queryParam
1112+
}
1113+
10821114

10831115
const isSplitView = Boolean(rowIndex !== undefined) || (configure && file?.name)
10841116
const rows = getRows()
@@ -1107,6 +1139,11 @@ const MapProject = () => {
11071139
const targetConceptFromCandidate = find(otherMatchedConcepts[rowIndex]?.results, {url: targetConcept?.url})
11081140
if(targetConceptFromCandidate)
11091141
targetConcept.search_meta = targetConceptFromCandidate.search_meta
1142+
else if(!targetConcept?.search_meta?.search_score) {
1143+
let meta = find(searchedConcepts[rowIndex], {url: targetConcept?.url})?.search_meta
1144+
if(meta?.search_score)
1145+
targetConcept.search_meta = meta
1146+
}
11101147

11111148
const labelDisplayedRows = ({ from, to, count }) => {
11121149
return `${from.toLocaleString()}${to.toLocaleString()} of ${count?.toLocaleString()}`;
@@ -1123,14 +1160,14 @@ const MapProject = () => {
11231160
snapOffset={0}
11241161
direction="horizontal"
11251162
cursor="col-resize"
1126-
style={{ display: 'flex', height: 'calc(100vh - 100px)' }}
1127-
gutter={() => {
1163+
style={{ display: 'flex', height: 'calc(100vh - 100px)' }}
1164+
gutter={() => {
11281165
const gutter = document.createElement('div');
11291166
gutter.className = 'gutter';
11301167
return gutter;
11311168
}}
11321169
>
1133-
<Paper component="div" className={isSplitView ? 'col-xs-6 split padding-0' : 'col-xs-12 split padding-0'} sx={{boxShadow: 'none', p: 0, backgroundColor: 'white', borderRadius: '10px', border: 'solid 0.3px', borderColor: 'surface.nv80', minHeight: 'calc(100vh - 100px) !important'}}>
1170+
<Paper component="div" className={isSplitView ? 'col-xs-6 split padding-0' : 'col-xs-12 split padding-0'} sx={{boxShadow: 'none', p: 0, backgroundColor: 'white', borderRadius: '10px', border: 'solid 0.3px', borderColor: 'surface.nv80', minHeight: 'calc(100vh - 100px) !important', overflow: 'auto'}}>
11341171
<Paper component="div" className='col-xs-12' sx={{backgroundColor: 'surface.main', boxShadow: 'none', padding: '4px 16px 8px 16px', borderRadius: '10px 10px 0 0', minWidth: '665px', ...((isConfigureInSplitView || !configure) ? {} : {height: 'calc(100vh - 125px) !important', overflow: 'auto'})}}>
11351172
{
11361173
configure && !file?.name &&
@@ -1611,6 +1648,12 @@ const MapProject = () => {
16111648
searchStr={searchStr}
16121649
setSearchStr={setSearchStr}
16131650
onSearch={searchCandidates}
1651+
facets={facets[rowIndex]}
1652+
appliedFacets={appliedFacets[rowIndex]}
1653+
setAppliedFacets={(filters) => {
1654+
setAppliedFacets({...appliedFacets, [rowIndex]: filters})
1655+
searchCandidates(null, null, null, null, filters)
1656+
}}
16141657
/>
16151658
}
16161659
{

src/components/map-projects/SearchCandidates.jsx

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
import React from 'react'
22
import TextField from '@mui/material/TextField'
33
import Button from '@mui/material/Button';
4-
4+
import Badge from '@mui/material/Badge';
5+
import IconButton from '@mui/material/IconButton';
6+
import FilterListIcon from '@mui/icons-material/FilterList';
57
import max from 'lodash/max'
8+
import isEmpty from 'lodash/isEmpty'
9+
import values from 'lodash/values'
10+
import flatten from 'lodash/flatten'
611

712
import { highlightTexts } from '../../common/utils';
813
import SearchResults from '../search/SearchResults';
14+
import SearchFilters from '../search/SearchFilters'
915
import Mappings from './Mappings'
1016
import Concept from './Concept'
1117

12-
const SearchCandidates = ({searchStr, setSearchStr, candidates, repo, repoVersion, rowIndex, concepts, setShowItem, showItem, isSelectedForMap, onMap, response, onSearch}) => {
18+
const SearchCandidates = ({searchStr, setSearchStr, candidates, repo, repoVersion, rowIndex, concepts, setShowItem, showItem, isSelectedForMap, onMap, response, onSearch, facets, appliedFacets, setAppliedFacets}) => {
19+
const [openFilters, setOpenFilters] = React.useState(openFilters)
1320
let total = parseInt(response?.headers?.num_found) || concepts?.length || 0
1421
const results = {total: total, pageSize: max([parseInt(response?.headers?.num_returned), 5]), page: parseInt(response?.headers?.page_number), pages: parseInt(response?.headers?.pages), results: response?.data || []}
1522

@@ -23,6 +30,11 @@ const SearchCandidates = ({searchStr, setSearchStr, candidates, repo, repoVersio
2330
return (
2431
<div className='col-xs-12 padding-0'>
2532
<div className='col-xs-12 padding-0' style={{display: 'flex', alignItems: 'center', margin: '16px 0'}}>
33+
<IconButton color={(isEmpty(appliedFacets) && !openFilters) ? undefined : 'primary'} style={{marginRight: '4px'}} onClick={() => setOpenFilters(!openFilters)} disabled={isEmpty(facets)}>
34+
<Badge badgeContent={flatten(values(appliedFacets).map(v => values(v))).length} color='primary'>
35+
<FilterListIcon sx={{color: (isEmpty(appliedFacets) && !openFilters) ? '#000': 'primary'}} />
36+
</Badge>
37+
</IconButton>
2638
<TextField
2739
autoFocus
2840
label='Search'
@@ -44,7 +56,18 @@ const SearchCandidates = ({searchStr, setSearchStr, candidates, repo, repoVersio
4456
Search
4557
</Button>
4658
</div>
47-
<div className='col-xs-12 padding-0' style={{display: 'flex', alignItems: 'center'}}>
59+
<div className='col-xs-12 padding-0' style={{display: 'flex'}}>
60+
{
61+
!isEmpty(facets) &&
62+
<div className='col-xs-5 padding-0' style={openFilters ? {borderRight: '1px solid lightgray', height: 'calc(100vh - 585px)', overflow: 'auto'} : {width: 0, display: 'none'}}>
63+
<SearchFilters
64+
resource='concepts'
65+
filters={facets}
66+
appliedFilters={appliedFacets || {}}
67+
onChange={setAppliedFacets}
68+
/>
69+
</div>
70+
}
4871
<SearchResults
4972
id={rowIndex}
5073
resultSize='small'
@@ -68,8 +91,8 @@ const SearchCandidates = ({searchStr, setSearchStr, candidates, repo, repoVersio
6891
resource='concepts'
6992
noSorting
7093
noToolbar
71-
rowsPerPageOptions={-1}
72-
resultContainerStyle={{height: 'calc(100vh - 582px)'}}
94+
rowsPerPageOptions={[]}
95+
resultContainerStyle={{height: 'calc(100vh - 630px)'}}
7396
onShowItemSelect={item => {
7497
setShowItem(item)
7598
setTimeout(() => {

src/components/search/SearchFilters.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const SearchFilters = ({filters, resource, onChange, kwargs, bgColor, appliedFil
123123

124124
return (
125125
<div className='col-xs-12 padding-0'>
126-
<div className='col-xs-12' style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', zIndex: 2, padding: '14px 0 0 0'}}>
126+
<div className='col-xs-12' style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', zIndex: 2, padding: 0}}>
127127
<span>
128128
<b>{t('search.filters')}</b>
129129
</span>
@@ -147,34 +147,34 @@ const SearchFilters = ({filters, resource, onChange, kwargs, bgColor, appliedFil
147147
padding: '2px 0 4px 0',
148148
}}
149149
>
150-
<ListSubheader sx={{p: 0, fontWeight: 'bold', background: bgColor, lineHeight: '30px'}}>{startCase(field)}</ListSubheader>
150+
<ListSubheader sx={{p: 0, fontWeight: 'bold', background: bgColor, lineHeight: '30px', fontSize: '11px'}}>{startCase(field)}</ListSubheader>
151151
{
152152
getFieldFilters(field, fieldFilters).map(value => {
153153
const labelId = `checkbox-list-label-${value[0]}`;
154154
const key = `${field}-${value[0]}`
155155

156156
return (
157157
<ListItemButton key={key} onClick={handleToggle(field, value)} sx={{p: '0 12px 0 4px'}} disabled={value[3] === true}>
158-
<ListItemIcon sx={{minWidth: '25px'}}>
158+
<ListItemIcon sx={{minWidth: '14px', '.MuiSvgIcon-root': {fontSize: '16px'}}}>
159159
<Checkbox
160160
size="small"
161161
edge="start"
162162
checked={isApplied(field, value)}
163163
tabIndex={-1}
164164
disableRipple
165165
inputProps={{ 'aria-labelledby': labelId }}
166-
style={{padding: '4px 8px'}}
166+
style={{padding: '2px 0 2px 6px'}}
167167
/>
168168
</ListItemIcon>
169-
<ListItemText id={labelId} primary={formattedName(field, value[0]) || 'None'} primaryTypographyProps={{style: {fontSize: '0.875rem'}}} style={{margin: 0}} />
169+
<ListItemText id={labelId} primary={formattedName(field, value[0]) || 'None'} primaryTypographyProps={{style: {fontSize: '0.8rem'}}} style={{margin: 0}} />
170170
<span style={{fontSize: '0.7rem'}}>{value[1].toLocaleString()}</span>
171171
</ListItemButton>
172172
);
173173
})}
174174
</List>
175175
{
176176
shouldShowExpand &&
177-
<Button size='small' onClick={() => toggleExpanded(field)} style={{textTransform: 'none'}} color='secondary' startIcon={isExpanded ? <UpIcon fontSize='inherit'/> : <DownIcon fontSize='inherit'/>}>
177+
<Button size='small' onClick={() => toggleExpanded(field)} style={{textTransform: 'none', fontSize: '10px'}} color='secondary' startIcon={isExpanded ? <UpIcon fontSize='inherit'/> : <DownIcon fontSize='inherit'/>}>
178178
{isExpanded ? t('common.hide') : `${t('common.show')} ${fieldFilters.length - 4} ${t('common.more').toLowerCase()}`}
179179
</Button>
180180
}

0 commit comments

Comments
 (0)