Skip to content

Commit 39f294c

Browse files
committed
OpenConceptLab/ocl_issues#2242 | project level filters
1 parent 4225c78 commit 39f294c

File tree

3 files changed

+97
-10
lines changed

3 files changed

+97
-10
lines changed

src/components/map-projects/ConfigurationForm.jsx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import Typography from '@mui/material/Typography'
3+
import Autocomplete from '@mui/material/Autocomplete'
34
import TextField from '@mui/material/TextField'
45
import FormHelperText from '@mui/material/FormHelperText'
56
import Button from '@mui/material/Button'
@@ -21,6 +22,7 @@ import SaveIcon from '@mui/icons-material/Save';
2122
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
2223

2324
import isEmpty from 'lodash/isEmpty'
25+
import omit from 'lodash/omit'
2426

2527
import { toV3URL } from '../../common/utils'
2628
import NamespaceDropdown from '../common/NamespaceDropdown'
@@ -44,7 +46,7 @@ const VisuallyHiddenInput = styled('input')({
4446
});
4547

4648

47-
const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, name, setName, description, setDescription, repo, onRepoChange, repoVersion, setRepoVersion, versions, mappedSources, targetSourcesFromRows, algo, onAlgoSelect, sx, algos, validColumns, columns, isValidColumnValue, updateColumn, configure, setConfigure, columnVisibilityModel, setColumnVisibilityModel, onSave, isSaving, matchAPI, setMatchAPI, matchAPIToken, setMatchAPIToken, candidatesScore, onScoreChange, semanticBatchSize, setSemanticBatchSize, includeDefaultFilter, setIncludeDefaultFilter }) => {
49+
const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, name, setName, description, setDescription, repo, onRepoChange, repoVersion, setRepoVersion, versions, mappedSources, targetSourcesFromRows, algo, onAlgoSelect, sx, algos, validColumns, columns, isValidColumnValue, updateColumn, configure, setConfigure, columnVisibilityModel, setColumnVisibilityModel, onSave, isSaving, matchAPI, setMatchAPI, matchAPIToken, setMatchAPIToken, candidatesScore, onScoreChange, semanticBatchSize, setSemanticBatchSize, includeDefaultFilter, setIncludeDefaultFilter, filters, setFilters, locales }) => {
4850
const [algoMenuAnchorEl, setAlgoMenuAnchorEl] = React.useState(null)
4951

5052
const onAlgoButtonClick = event => setAlgoMenuAnchorEl(algoMenuAnchorEl ? null : event.currentTarget)
@@ -54,6 +56,7 @@ const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, n
5456
}
5557

5658
const isLLMAlgoNotAllowed = !repoVersion?.match_algorithms?.includes('llm')
59+
const appliedLocales = filters?.locale ? filters?.locale?.split(',') : []
5760

5861
return (
5962
<div className='col-xs-12' style={{padding: '8px 0', ...sx}}>
@@ -148,10 +151,48 @@ const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, n
148151
{`${repo?.owner}:${repo?.short_code || repo?.id}:${repoVersion?.id || repo?.version || repo?.id} is not configured to run Semantic Search`}
149152
</FormHelperText>
150153
}
154+
{
155+
locales?.length > 0 &&
156+
<Autocomplete
157+
multiple
158+
size='small'
159+
id="locale"
160+
options={locales}
161+
getOptionLabel={(option) => option}
162+
value={appliedLocales}
163+
onChange={(event, values) => {
164+
setFilters({...filters, locale: values.join(',')})
165+
}}
166+
sx={{marginTop: '12px'}}
167+
renderInput={(params) => (
168+
<TextField
169+
{...params}
170+
size='small'
171+
label="Filter Name Locales"
172+
helperText="Note: Restricting candidates to specific languages limits cross-lingual matching capabilities, but may improve the accuracy of results for certain datasets, especially if the input data is in the same language as a target repository's default language."
173+
/>
174+
)}
175+
/>
176+
}
151177
{
152178
!isEmpty(repoVersion?.meta?.display?.default_filter) && repoVersion?.meta?.display?.default_filter &&
153179
<FormHelperText sx={{marginLeft: '8px'}}>
154-
<FormControlLabel size='small' control={<Checkbox size='small' checked={includeDefaultFilter} onChange={event => setIncludeDefaultFilter(event.target.checked)} sx={{padding: '8px 4px'}} />} label="Default Filter" />
180+
<FormControlLabel
181+
size='small'
182+
control={
183+
<Checkbox
184+
size='small'
185+
checked={includeDefaultFilter}
186+
sx={{padding: '8px 4px'}}
187+
onChange={() => {
188+
const newValue = !includeDefaultFilter
189+
setIncludeDefaultFilter(newValue);
190+
setFilters(newValue ? {...filters, ...repoVersion.meta.display.default_filter} : omit(filters, Object.keys(repoVersion.meta.display.default_filter)))
191+
}}
192+
/>
193+
}
194+
label="Default Filter"
195+
/>
155196
<div style={{whiteSpace: 'pre'}}>{JSON.stringify(repoVersion.meta.display.default_filter, undefined, 2)}</div>
156197
</FormHelperText>
157198
}

src/components/map-projects/MapProject.jsx

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ const MapProject = () => {
152152
const [matchAPIToken, setMatchAPIToken] = React.useState('')
153153
const [semanticBatchSize, setSemanticBatchSize] = React.useState(SEMANTIC_BATCH_SIZE)
154154
const [candidatesScore, setCandidatesScore] = React.useState({recommended: 100, available: 70})
155+
const [filters, setFilters] = React.useState({})
155156

156157
const abortRef = React.useRef(false);
157158

@@ -183,6 +184,7 @@ const MapProject = () => {
183184
const [repo, setRepo] = React.useState(false)
184185
const [repoVersion, setRepoVersion] = React.useState(false)
185186
const [mappedSources, setMappedSources] = React.useState([])
187+
const [locales, setLocales] = React.useState([])
186188
const [versions, setVersions] = React.useState([])
187189
const [conceptCache, setConceptCache] = React.useState({})
188190
const [allMapTypes, setAllMapTypes] = React.useState([])
@@ -230,6 +232,11 @@ const MapProject = () => {
230232
setPermissionDenied(false)
231233
}, [params.projectId])
232234

235+
React.useEffect(() => {
236+
const isDefaultApplied = isRepoDefaultFilterApplied(repoVersion)
237+
setIncludeDefaultFilter(Boolean(isDefaultApplied))
238+
}, [repoVersion, project])
239+
233240

234241
const fetchAndSetProject = () => {
235242
setLoadingProject(true)
@@ -241,6 +248,7 @@ const MapProject = () => {
241248
setLoadingProject(false)
242249
return
243250
}
251+
setFilters(response.data?.filters || {})
244252
if(response.data.url) {
245253
APIService.new().overrideURL(response.data.url).appendToUrl('logs/').get().then(response => setLogs(response.data.logs || []))
246254
}
@@ -297,6 +305,11 @@ const MapProject = () => {
297305
})
298306
}
299307

308+
const isRepoDefaultFilterApplied = version => {
309+
const defaultFilter = version?.meta?.display?.default_filter || {};
310+
return !isEmpty(defaultFilter) && Object.keys(defaultFilter).every(key => has((project.filters || {}), key));
311+
}
312+
300313
const fetchMapTypes = () => APIService.orgs('OCL').sources('MapTypes').appendToUrl('concepts/lookup/').get().then(response => setAllMapTypes(response.data?.map(d => d.id)))
301314

302315
const alertUser = (e) => {
@@ -582,6 +595,7 @@ const MapProject = () => {
582595
formData.append('match_api_url', '')
583596
formData.append('match_api_token', '')
584597
}
598+
formData.append('filters', JSON.stringify(getFilters()))
585599
let service = APIService.new().overrideURL(owner).appendToUrl('map-projects/')
586600
if(project?.id)
587601
service = service.appendToUrl(project.id + '/').put(formData, null, {"Content-Type": "multipart/form-data"})
@@ -631,6 +645,12 @@ const MapProject = () => {
631645
recurse(0, 1, 0, [])
632646
}
633647

648+
const fetchLocaleDistribution = url => {
649+
if(!url)
650+
return
651+
APIService.new().overrideURL(url).appendToUrl('summary/').get(null, null, {verbose: true, distribution: 'name_locale'}).then(response => setLocales(map(response?.data?.distribution?.name_locale, 'locale')))
652+
}
653+
634654
const _fetchMappedSources = (
635655
url, limit, offset, page, callback
636656
) => {
@@ -640,6 +660,7 @@ const MapProject = () => {
640660
const onRepoVersionChange = version => {
641661
setRepoVersion(version)
642662
if(version?.version_url) {
663+
fetchLocaleDistribution(version.version_url)
643664
fetchMappedSources(version.version_url)
644665
updateAlgosByRepoVersion(version)
645666
}
@@ -662,6 +683,12 @@ const MapProject = () => {
662683
setAlgoMenuAnchorEl(null)
663684
}
664685

686+
const getFilters = () => {
687+
let defaultFilters = (repoVersion?.meta?.display?.default_filter || {})
688+
let allFilters = {...filters, ...defaultFilters}
689+
return includeDefaultFilter ? allFilters : omit(allFilters, Object.keys(defaultFilters))
690+
}
691+
665692
const getPayloadForMatching = (rows, _repo) => {
666693
return {
667694
rows: map(rows, row => prepareRow(row)),
@@ -673,7 +700,7 @@ const MapProject = () => {
673700
'source': _repo.short_code || _repo.id
674701
},
675702
map_config: getMapConfigs(),
676-
filter: includeDefaultFilter ? repoVersion?.meta?.display?.default_filter || {} : {}
703+
filter: getFilters()
677704
}
678705
}
679706

@@ -1060,6 +1087,10 @@ const MapProject = () => {
10601087

10611088
if(repo?.id) {
10621089
fetchOtherCandidates(csvRow)
1090+
const _filters = getFilters()
1091+
if(!appliedFacets[csvRow.__index] && !isEmpty(_filters) && _filters) {
1092+
setAppliedFacets({...appliedFacets, [csvRow.__index]: getAppliedFacetFromQueryParam(_filters)})
1093+
}
10631094
}
10641095

10651096
const el = document.querySelector(`div[data-id="${csvRow.__index}"]`)
@@ -1149,7 +1180,7 @@ const MapProject = () => {
11491180
fetchOtherCandidates()
11501181
}
11511182
if(newValue === 'search' && isEmpty(facets[rowIndex]))
1152-
getFacets()
1183+
getFacets(true)
11531184
}
11541185

11551186
const onDecisionChange = (event, newValue) => {
@@ -1282,7 +1313,6 @@ const MapProject = () => {
12821313
q: searchStr,
12831314
page: page || 1,
12841315
includeRetired: includeRetired === undefined ? retired : includeRetired,
1285-
conceptFilterDefault: includeDefaultFilter,
12861316
...getFacetQueryParam(appliedFilters || appliedFacets[rowIndex]),
12871317
}).then(response => {
12881318
let items = response.data
@@ -1300,13 +1330,13 @@ const MapProject = () => {
13001330
});
13011331
}
13021332

1303-
const getFacets = _row => {
1333+
const getFacets = firstLoad => {
13041334
APIService.new().overrideURL(repoVersion.version_url).appendToUrl('concepts/').get(null, null, {
1305-
q: searchStr,
1335+
q: firstLoad ? '' : searchStr,
13061336
includeRetired: retired,
13071337
facetsOnly: true
13081338
}).then(response => {
1309-
setFacets({...facets, [_row?.__index === undefined ? row.__index : _row.__index]: response?.data?.facets?.fields || {}})
1339+
setFacets({...facets, [row.__index]: response?.data?.facets?.fields || {}})
13101340
})
13111341
}
13121342

@@ -1324,6 +1354,15 @@ const MapProject = () => {
13241354
return queryParam
13251355
}
13261356

1357+
const getAppliedFacetFromQueryParam = filters => {
1358+
const applied = {}
1359+
forEach(filters, (value, field) => {
1360+
applied[field] = {}
1361+
forEach(value.split(','), val => applied[field][val] = true)
1362+
})
1363+
return applied
1364+
}
1365+
13271366

13281367
const isSplitView = Boolean(rowIndex !== undefined) || (configure && file?.name)
13291368
const rows = getRows()
@@ -1458,6 +1497,9 @@ const MapProject = () => {
14581497
onScoreChange={setCandidatesScore}
14591498
includeDefaultFilter={includeDefaultFilter}
14601499
setIncludeDefaultFilter={setIncludeDefaultFilter}
1500+
filters={filters}
1501+
setFilters={setFilters}
1502+
locales={locales}
14611503
/>
14621504
</div>
14631505
}
@@ -1828,6 +1870,9 @@ const MapProject = () => {
18281870
onScoreChange={setCandidatesScore}
18291871
includeDefaultFilter={includeDefaultFilter}
18301872
setIncludeDefaultFilter={setIncludeDefaultFilter}
1873+
filters={filters}
1874+
setFilters={setFilters}
1875+
locales={locales}
18311876
/>
18321877
</div> :
18331878
(
@@ -1953,6 +1998,7 @@ const MapProject = () => {
19531998
setSearchStr={setSearchStr}
19541999
facets={facets[rowIndex]}
19552000
appliedFacets={appliedFacets[rowIndex]}
2001+
filters={getFilters()}
19562002
isLoading={isLoadingInDecisionView}
19572003
setAppliedFacets={(filters) => {
19582004
setAppliedFacets({...appliedFacets, [rowIndex]: filters})

src/components/map-projects/Search.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Mappings from './Mappings'
2222
import Concept from './Concept'
2323
import MapButton from './MapButton'
2424

25-
const Search = ({searchStr, setSearchStr, onSearch, repo, repoVersion, concepts, setShowItem, showItem, isSelectedForMap, onMap, response, facets, appliedFacets, setAppliedFacets, isLoading}) => {
25+
const Search = ({searchStr, setSearchStr, onSearch, repo, repoVersion, concepts, setShowItem, showItem, isSelectedForMap, onMap, response, facets, appliedFacets, setAppliedFacets, isLoading, filters}) => {
2626
const [openFilters, setOpenFilters] = React.useState(openFilters)
2727
const [display, setDisplay] = React.useState('card')
2828
let total = parseInt(response?.headers?.num_found) || concepts?.length || 0
@@ -120,7 +120,7 @@ const Search = ({searchStr, setSearchStr, onSearch, repo, repoVersion, concepts,
120120
filters={facets}
121121
appliedFilters={appliedFacets || {}}
122122
onChange={setAppliedFacets}
123-
repoDefaultFilters={repoVersion?.meta?.display?.default_filter}
123+
repoDefaultFilters={filters}
124124
properties={repoVersion?.meta?.display?.concept_summary_properties}
125125
propertyFilters={repoVersion?.filters}
126126
heightToSubtract={523}

0 commit comments

Comments
 (0)