diff --git a/src/components/search/concept-modal/concept-modal.css b/src/components/search/concept-modal/concept-modal.css
index 62f82025..c429c2ed 100644
--- a/src/components/search/concept-modal/concept-modal.css
+++ b/src/components/search/concept-modal/concept-modal.css
@@ -58,6 +58,14 @@
margin-bottom: -16px;
}
+.explanation-score-progress {
+ display: inline-flex !important;
+ align-items: center;
+}
+.explanation-score-progress .ant-progress-outer {
+ display: inline-flex;
+}
+
@media (min-width: 600px) {
.tab-name {
display: inline;
diff --git a/src/components/search/concept-modal/concept-modal.js b/src/components/search/concept-modal/concept-modal.js
index fd3ea6e5..5b58a108 100644
--- a/src/components/search/concept-modal/concept-modal.js
+++ b/src/components/search/concept-modal/concept-modal.js
@@ -9,9 +9,10 @@ import CustomIcon, {
ExportOutlined as ExternalLinkIcon,
FullscreenOutlined as FullscreenLayoutIcon,
UnorderedListOutlined as CdesIcon,
+ QuestionCircleOutlined as ExplanationIcon,
ArrowLeftOutlined, InfoCircleOutlined
} from '@ant-design/icons'
-import { CdesTab, OverviewTab, StudiesTab, KnowledgeGraphsTab, TranQLTab } from './tabs'
+import { CdesTab, OverviewTab, StudiesTab, KnowledgeGraphsTab, TranQLTab, ExplanationTab } from './tabs'
import { useHelxSearch } from '../'
import { BouncingDots } from '../../'
import { useAnalytics, useEnvironment } from '../../../contexts'
@@ -92,16 +93,17 @@ export const ConceptModalBody = ({ result }) => {
)
const cdeTitle = (
- CDEs { cdes ? `(${ Object.keys(cdes).length })` : }
+ CDEs { !cdesLoading ? `(${ Object.keys(cdes ?? []).length })` : }
)
const tabs = {
- 'overview': { title: 'Overview', icon: , content: , },
- 'studies': { title: studyTitle, icon: , content: , },
- 'cdes': { title: cdeTitle, icon: , content: },
- 'kgs': { title: 'Knowledge Graphs', icon: , content: , },
- 'tranql': { title: 'TranQL', icon: , content: }
+ 'overview': { title: 'Overview', icon: , content: , },
+ 'studies': { title: studyTitle, icon: , content: , },
+ 'cdes': { title: cdeTitle, icon: , content: },
+ 'kgs': { title: 'Knowledge Graphs', icon: , content: , },
+ 'explanation': { title: 'Explanation', icon: , content: },
+ 'tranql': { title: 'TranQL', icon: , content: }
}
const links = {
'robokop' : { title: 'ROBOKOP', icon: , url: "https://robokop.renci.org/" }
diff --git a/src/components/search/concept-modal/tabs/cdes/cde-item.js b/src/components/search/concept-modal/tabs/cdes/cde-item.js
index fa4b2f7d..13d96cbe 100644
--- a/src/components/search/concept-modal/tabs/cdes/cde-item.js
+++ b/src/components/search/concept-modal/tabs/cdes/cde-item.js
@@ -26,7 +26,7 @@ export const CdeItem = ({ cde, cdeRelatedConcepts, highlight }) => {
), [cdeRelatedConcepts, cde])
const Highlighter = useCallback(({ ...props }) => (
- <_Highlighter searchWords={highlight} {...props}/>
+ <_Highlighter autoEscape={ true } searchWords={highlight} {...props}/>
), [highlight])
return (
diff --git a/src/components/search/concept-modal/tabs/cdes/related-concepts/related-concept-tag.js b/src/components/search/concept-modal/tabs/cdes/related-concepts/related-concept-tag.js
index 4ad35687..75e16c68 100644
--- a/src/components/search/concept-modal/tabs/cdes/related-concepts/related-concept-tag.js
+++ b/src/components/search/concept-modal/tabs/cdes/related-concepts/related-concept-tag.js
@@ -38,7 +38,7 @@ export const RelatedConceptTag = ({ concept, highlight }) => {
setShowOptions(true)
}}>
-
+
diff --git a/src/components/search/concept-modal/tabs/explanation.js b/src/components/search/concept-modal/tabs/explanation.js
new file mode 100644
index 00000000..5f9bda09
--- /dev/null
+++ b/src/components/search/concept-modal/tabs/explanation.js
@@ -0,0 +1,250 @@
+import { useMemo, useRef, useState } from 'react'
+import { Button, Checkbox, Divider, Progress, Space, Switch, Typography } from 'antd'
+import { presetPalettes } from '@ant-design/colors'
+import { Pie } from '@ant-design/plots'
+import { InfoTooltip } from '../../..'
+
+const { Title, Text } = Typography
+
+// Show the first 6 score components, unless show more is pressed.
+const SHOW_MORE_CUTOFF = 6
+
+const palette = [
+ presetPalettes.blue,
+ presetPalettes.gold,
+ presetPalettes.green,
+ presetPalettes.purple,
+ presetPalettes.volcano,
+ presetPalettes.cyan,
+ presetPalettes.magenta,
+ presetPalettes.yellow,
+ presetPalettes.red,
+ presetPalettes.lime,
+ presetPalettes.geekblue
+].map((palette) => palette[5])
+
+const parseScoreDetail = ({ value, description, details }) => {
+ if (value === 0) return null
+ if (description === "sum of:") {
+ return details.flatMap((detail) => parseScoreDetail(detail))
+ }
+
+ const explainPattern = /^weight\((?.+):(?.+) in (?\d+)\) \[(?.+)\], result of:$/
+ const match = description.match(explainPattern)
+ if (match) {
+ let { fieldName, searchTerm, segmentNumber, similarityMetric } = match.groups
+ if (searchTerm.startsWith(`"`) && searchTerm.endsWith(`"`)) searchTerm = searchTerm.slice(1, -1)
+ return {
+ fieldMatch: fieldName,
+ termMatch: searchTerm,
+ source: description,
+ value
+ }
+ } else {
+ console.log("Failed to parse score explanation:", description)
+ return {
+ fieldMatch: null,
+ termMatch: null,
+ source: description,
+ value
+ }
+ }
+}
+
+export const ExplanationTab = ({ result }) => {
+ const { explanation } = result
+
+ const [showMore, setShowMore] = useState(false)
+ const [advancedBreakdown, setAdvancedBreakdown] = useState(false)
+ const pieRef = useRef()
+ const totalScore = useMemo(() => explanation.value, [explanation.value])
+ const scoreData = useMemo(() => (parseScoreDetail(explanation)
+ .filter((detail) => detail !== null)
+ // Reduce duplicate details into single details.
+ .reduce((acc, cur) => {
+ const existingDetail = acc.find((detail) => detail.source === cur.source)
+ if (!existingDetail) acc.push(cur)
+ else {
+ // If the exact detail already exists, add the scores.
+ existingDetail.value += cur.value
+ }
+ return acc
+ }, [])
+ // Reduce details down further into single field matches, if advanced breakdown is disabled.
+ // E.g. `name:heart` and `name:heart disease` would get merged into the same detail at this step.
+ .reduce((acc, cur) => {
+ if (advancedBreakdown) {
+ acc.push(cur)
+ return acc
+ }
+ const existingDetailWithField = acc.find((detail) => detail.fieldMatch === cur.fieldMatch)
+ if (!existingDetailWithField) acc.push(cur)
+ else {
+ // If a detail exists with the current field match, and not in advanced breakdown, add the scores.
+ if (Array.isArray(existingDetailWithField.termMatch)) existingDetailWithField.termMatch.push(cur.termMatch)
+ else existingDetailWithField.termMatch = [existingDetailWithField.termMatch, cur.termMatch]
+ existingDetailWithField.value += cur.value
+ }
+ return acc
+ }, [])
+ // Reduce details into chart data
+ .reduce((acc, cur) => {
+ const { fieldMatch, termMatch, source, value } = cur
+ const [fieldMatchName, fieldMatchDescription] = (
+ fieldMatch === "name" ? ["Name", "The name of this concept"]
+ : fieldMatch === "description" ? ["Description", "The description of this concept"]
+ : fieldMatch === "search_terms" ? ["Search terms", "Synonymous names for this concept"]
+ : fieldMatch === "optional_terms" ? ["Related terms", "Search terms for concepts related to this concept"]
+ : ["", ""]
+ )
+ const advancedBreakdownString = ` ${ fieldMatchName.endsWith("s") ? "contain" : "contains"} the term "${ termMatch }"`
+ if (fieldMatch && termMatch) acc.push({
+ name: `${ fieldMatchName }`,
+ description: `${ fieldMatchDescription }${ advancedBreakdown ? advancedBreakdownString : ""}`,
+ key: source,
+ matchedField: fieldMatch,
+ matchedTerms: termMatch,
+ failedParse: false,
+ value
+ })
+ else acc.push({
+ name: "Unknown",
+ description: "Could not parse explanation for this score component.",
+ key: source,
+ matchedField: null,
+ matchedTerms: null,
+ failedParse: true,
+ value
+ })
+ return acc
+ }, [])
+ .sort((a, b) => b.value - a.value)
+ ), [explanation, advancedBreakdown])
+ const colorMap = useMemo(() => palette.slice(0, scoreData.length), [scoreData])
+ const pieConfig = useMemo(() => ({
+ data: scoreData,
+ // appendPadding: 10,
+ autoFit: false,
+ height: 310,
+ width: 400,
+ angleField: "value",
+ colorField: "key",
+ radius: 1,
+ innerRadius: 0.70,
+ renderer: "svg",
+ legend: false,
+ statistic: {
+ title: {
+ style: {
+ fontSize: "1em"
+ }
+ },
+ content: {
+ offsetY: 4,
+ content: explanation.value.toFixed(1),
+ style: {
+ fontSize: "1em"
+ }
+ }
+ },
+ label: {
+ type: "inner",
+ offset: "-50%",
+ style: {
+ textAlign: "center"
+ },
+ autoRotate: false,
+ formatter: (v) => v.value.toFixed(1)
+ },
+ tooltip: {
+ formatter: (datum) => {
+ const { name, value } = scoreData.find((d) => d.key === datum.key)
+ return { name, value }
+ }
+ },
+ color: colorMap
+ }), [scoreData, colorMap, explanation])
+ return (
+
+
+
+
+ Score breakdown
+
+
+ Why am I seeing this result?
+
+
+
+ setAdvancedBreakdown(!advancedBreakdown) } />
+ Advanced
+
+
+
+
+
+ {
+ (showMore ? scoreData : scoreData.slice(0, SHOW_MORE_CUTOFF - 1)).map((detail, i) => (
+
+
+
+ { detail.name }
+
+
+
+
+ { detail.description }
+ {/* { !detail.failedParse && (
+
+ { Array.isArray(detail.matchedTerms) ? detail.matchedTerms.join("/") : detail.matchedTerms }
+ matched with
+ { result[detail.matchedField] }
+
+ }
+ placement="bottom"
+ trigger="hover"
+ iconProps={{ style: { marginLeft: 6, fontSize: 14, color: "rgba(0, 0, 0, 0.45)" } }}
+ />
+ ) } */}
+
+
+ ))
+ }
+ { scoreData.length > SHOW_MORE_CUTOFF && (
+
+ ) }
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/search/concept-modal/tabs/index.js b/src/components/search/concept-modal/tabs/index.js
index 574c5984..bbceb139 100644
--- a/src/components/search/concept-modal/tabs/index.js
+++ b/src/components/search/concept-modal/tabs/index.js
@@ -2,5 +2,6 @@ export * from './cdes'
export * from './knowledge-graphs'
export * from './overview'
export * from './studies'
+export * from './explanation'
export * from './tranql'
export * from './robokop'
\ No newline at end of file
diff --git a/src/components/search/concept-modal/tabs/studies/study-variable.js b/src/components/search/concept-modal/tabs/studies/study-variable.js
index dd092abf..c9ddeee3 100644
--- a/src/components/search/concept-modal/tabs/studies/study-variable.js
+++ b/src/components/search/concept-modal/tabs/studies/study-variable.js
@@ -6,11 +6,11 @@ const { Text } = Typography
export const StudyVariable = ({ variable, highlight, ...props }) => (
)
\ No newline at end of file
diff --git a/src/components/search/concept-modal/tabs/studies/study.js b/src/components/search/concept-modal/tabs/studies/study.js
index a58d5181..c3fb3d53 100644
--- a/src/components/search/concept-modal/tabs/studies/study.js
+++ b/src/components/search/concept-modal/tabs/studies/study.js
@@ -20,7 +20,7 @@ export const Study = ({ study, highlight, collapsed, ...panelProps }) => {
- { ` ` }
+ { ` ` }
({ study.c_id })
}
diff --git a/src/components/search/context.js b/src/components/search/context.js
index 4c97a8d3..8d6fe84a 100644
--- a/src/components/search/context.js
+++ b/src/components/search/context.js
@@ -29,6 +29,7 @@ export const HelxSearch = ({ children }) => {
const [isLoadingConcepts, setIsLoadingConcepts] = useState(false);
const [error, setError] = useState({})
const [conceptPages, setConceptPages] = useState({})
+ const [conceptTypes, setConceptTypes] = useState({})
// const [concepts, setConcepts] = useState([])
const [totalConcepts, setTotalConcepts] = useState(0)
const [currentPage, setCurrentPage] = useState(1)
@@ -52,6 +53,7 @@ export const HelxSearch = ({ children }) => {
const [searchHistory, setSearchHistory] = useLocalStorage('search_history', [])
/** Abort controllers */
+ const fetchConceptsController = useRef()
const searchSelectedResultController = useRef()
// const selectedResultLoading = useMemo(() => selectedResult && selectedResult.loading === true, [selectedResult])
@@ -90,10 +92,11 @@ export const HelxSearch = ({ children }) => {
}
}
- const executeConceptSearch = async ({ query, offset, size }, axiosOptions) => {
+ const executeConceptSearch = async ({ query, types, offset, size }, axiosOptions) => {
const params = {
index: 'concepts_index',
query,
+ types,
offset,
size
}
@@ -148,30 +151,10 @@ export const HelxSearch = ({ children }) => {
}
}, [executeConceptSearch, validationReducer])
- const filteredConceptPages = useMemo(() => {
- if (typeFilter === null) return conceptPages
- return Object.fromEntries(Object.entries(conceptPages).map(([page, concepts]) => {
- return [
- page,
- concepts.filter((concept) => concept.type === typeFilter)
- ]
- }))
- }, [conceptPages, typeFilter])
-
- const conceptTypes = useMemo(() => Object.values(conceptPages).flat().reduce((acc, cur) => {
- if (!acc.includes(cur.type)) acc.push(cur.type)
- return acc
- }, []), [conceptPages])
- const conceptTypeCounts = useMemo(() => Object.values(conceptPages).flat().reduce((acc, cur) => {
- if (!acc.hasOwnProperty(cur.type)) acc[cur.type] = 0
- acc[cur.type] += 1
- return acc
- }, {}), [conceptPages])
-
const concepts = useMemo(() => {
- if (!filteredConceptPages[currentPage]) return []
- else return filteredConceptPages[currentPage]
- }, [filteredConceptPages, currentPage])
+ if (!conceptPages[currentPage]) return []
+ else return conceptPages[currentPage]
+ }, [conceptPages, currentPage])
const setLayout = (newLayout) => {
// Only track when layout changes
@@ -228,6 +211,7 @@ export const HelxSearch = ({ children }) => {
useEffect(() => {
setConceptPages({})
+ setConceptTypes({})
setError({})
setTypeFilter(null)
setSelectedResult(null)
@@ -235,23 +219,36 @@ export const HelxSearch = ({ children }) => {
setVariableResults([])
}, [query])
+ useEffect(() => {
+ setConceptPages({})
+ setCurrentPage(1)
+ setError({})
+ }, [typeFilter])
useEffect(() => {
const fetchConcepts = async () => {
if (conceptPages[currentPage]) {
return
}
- console.log("Load page", query, currentPage)
+
+ fetchConceptsController.current?.abort()
+ fetchConceptsController.current = new AbortController()
+
setIsLoadingConcepts(true)
- // await new Promise((resolve) => setTimeout(resolve, 2500))
const startTime = Date.now()
try {
const result = await executeConceptSearch({
query: query,
+ types: typeFilter ? [typeFilter] : undefined,
offset: (currentPage - 1) * PER_PAGE,
size: PER_PAGE
+ }, {
+ signal: fetchConceptsController.current.signal
})
if (result && result.hits) {
- const unsortedHits = result.hits.hits.map(r => r._source)
+ const unsortedHits = result.hits.hits.map(r => ({
+ ...r._source,
+ explanation: r._explanation
+ }))
// gather invalid concepts: remove from rendered concepts and dump to console.
let hits = unsortedHits.reduce(validationReducer, { valid: [], invalid: [] })
if (hits.invalid.length) {
@@ -263,6 +260,7 @@ export const HelxSearch = ({ children }) => {
newConceptPages[currentPage] = hits.valid
// setSelectedResult(null)
setConceptPages(newConceptPages)
+ setConceptTypes(result.concept_types)
setTotalConcepts(result.total_items)
// setConcepts(hits.valid)
setIsLoadingConcepts(false)
@@ -270,25 +268,26 @@ export const HelxSearch = ({ children }) => {
} else {
const newConceptPages = { ...conceptPages }
newConceptPages[currentPage] = []
- // setSelectedResult(null)
setConceptPages(newConceptPages)
- // setConcepts([])
+ setConceptTypes({})
setTotalConcepts(0)
setIsLoadingConcepts(false)
analyticsEvents.searchExecuted(query, Date.now() - startTime, 0)
}
} catch (error) {
- console.log(error)
- setError({ message: 'An error occurred!' })
- setTotalConcepts(0)
- setIsLoadingConcepts(false)
- analyticsEvents.searchExecuted(query, Date.now() - startTime, 0, error)
+ if (error.name !== "CanceledError") {
+ console.log(error)
+ setError({ message: 'An error occurred!' })
+ setTotalConcepts(0)
+ setIsLoadingConcepts(false)
+ analyticsEvents.searchExecuted(query, Date.now() - startTime, 0, error)
+ }
}
}
if (query) {
fetchConcepts()
}
- }, [query, currentPage, conceptPages, helxSearchUrl, analyticsEvents])
+ }, [query, currentPage, conceptPages, typeFilter, helxSearchUrl, analyticsEvents])
useEffect(() => {
setPageCount(Math.ceil(totalConcepts / PER_PAGE))
@@ -486,13 +485,13 @@ export const HelxSearch = ({ children }) => {
fetchKnowledgeGraphs, fetchCDEs, fetchVariablesForConceptId,
inputRef,
error, isLoadingConcepts,
- concepts, totalConcepts, conceptPages: filteredConceptPages,
+ concepts, totalConcepts, conceptPages,
currentPage, setCurrentPage, perPage: PER_PAGE, pageCount,
selectedResult, setSelectedResult, searchSelectedResult,
layout, setLayout, setFullscreenResult,
typeFilter, setTypeFilter,
searchHistory, setSearchHistory,
- conceptTypes, conceptTypeCounts,
+ conceptTypes,
variableStudyResults, variableStudyResultCount,
variableError, variableResults, isLoadingVariableResults,
totalVariableResults
diff --git a/src/components/search/form/form.js b/src/components/search/form/form.js
index 6381034f..154091b6 100644
--- a/src/components/search/form/form.js
+++ b/src/components/search/form/form.js
@@ -175,7 +175,7 @@ export const SearchForm = ({ type=undefined, ...props }) => {
return (
-
+
)
@@ -225,7 +225,7 @@ export const SearchForm = ({ type=undefined, ...props }) => {
suffix={
type === MINIMAL ? (
) : undefined
diff --git a/src/components/search/knowledge-graphs/knowledge-graphs.js b/src/components/search/knowledge-graphs/knowledge-graphs.js
index f63f635c..cf465b55 100644
--- a/src/components/search/knowledge-graphs/knowledge-graphs.js
+++ b/src/components/search/knowledge-graphs/knowledge-graphs.js
@@ -21,7 +21,7 @@ const KnowledgeGraph = ({ graph, highlight }) => {
}, [graph])
const Highlighter = useCallback(({ ...props }) => (
- <_Highlighter searchWords={highlight} {...props}/>
+ <_Highlighter autoEscape={ true } searchWords={highlight} {...props}/>
), [highlight])
return interactions.map((interaction, i) => (
diff --git a/src/components/search/results/concepts-grid-layout/concept-search-results.js b/src/components/search/results/concepts-grid-layout/concept-search-results.js
index 2c5aa48b..0f53cf3d 100644
--- a/src/components/search/results/concepts-grid-layout/concept-search-results.js
+++ b/src/components/search/results/concepts-grid-layout/concept-search-results.js
@@ -9,13 +9,13 @@ const { Text } = Typography
const { useBreakpoint } = AntGrid
export const ConceptSearchResults = () => {
- const { query, conceptPages, perPage, currentPage, pageCount, typeFilter,
+ const { query, conceptPages, perPage, currentPage, pageCount,
isLoadingConcepts, error, setCurrentPage, setSelectedResult } = useHelxSearch()
const { md } = useBreakpoint();
const concepts = useMemo(() => Object.values(conceptPages).flat(), [conceptPages])
const hasMore = useMemo(() => (
- !typeFilter && !isLoadingConcepts && (currentPage < pageCount || pageCount === 0)
- ), [typeFilter, isLoadingConcepts, currentPage, pageCount])
+ !isLoadingConcepts && (currentPage < pageCount || pageCount === 0)
+ ), [isLoadingConcepts, currentPage, pageCount])
const getNextPage = useCallback(() => {
setCurrentPage(currentPage + 1)
}, [currentPage])
@@ -62,12 +62,8 @@ export const ConceptSearchResults = () => {
currentPage === pageCount ? (
null
) : (
- typeFilter ? (
- Disable filters to load more results.
- ) : (
- (currentPage === 0 || currentPage < pageCount || isLoadingConcepts) && (
-
- )
+ (currentPage === 0 || currentPage < pageCount || isLoadingConcepts) && (
+
)
)
}
diff --git a/src/components/search/results/expanded-results-layout/expanded-results-sidebar.js b/src/components/search/results/expanded-results-layout/expanded-results-sidebar.js
index 5be0de16..e1ff4b4f 100644
--- a/src/components/search/results/expanded-results-layout/expanded-results-sidebar.js
+++ b/src/components/search/results/expanded-results-layout/expanded-results-sidebar.js
@@ -21,7 +21,7 @@ export const ExpandedResultsSidebar = ({ expanded, setExpanded }) => {
const {
conceptPages, selectedResult, setSelectedResult,
pageCount, isLoadingConcepts, setLayout,
- currentPage, setCurrentPage, typeFilter
+ currentPage, setCurrentPage
} = useHelxSearch()
const { md } = useBreakpoint()
const cardRefs = useRef({})
@@ -29,8 +29,8 @@ export const ExpandedResultsSidebar = ({ expanded, setExpanded }) => {
const concepts = useMemo(() => Object.values(conceptPages).flat(), [conceptPages])
const hasMore = useMemo(() => (
- !typeFilter && !isLoadingConcepts && (currentPage < pageCount || pageCount === 0)
- ), [typeFilter, isLoadingConcepts, currentPage, pageCount])
+ !isLoadingConcepts && (currentPage < pageCount || pageCount === 0)
+ ), [isLoadingConcepts, currentPage, pageCount])
const getNextPage = useCallback(() => {
setCurrentPage(currentPage + 1)
@@ -101,16 +101,11 @@ export const ExpandedResultsSidebar = ({ expanded, setExpanded }) => {
{
currentPage === pageCount ? (
null
- ) : (
- typeFilter ? (
- Disable filters to load more results.
- ) : (
- (currentPage === 0 || currentPage < pageCount || isLoadingConcepts) && (
-
- )
+ ) : ((currentPage === 0 || currentPage < pageCount || isLoadingConcepts) && (
+
)
)
}
diff --git a/src/components/search/results/results-header/index.js b/src/components/search/results/results-header/index.js
index 9754ed49..a1e41d40 100644
--- a/src/components/search/results/results-header/index.js
+++ b/src/components/search/results/results-header/index.js
@@ -23,7 +23,7 @@ export const ResultsHeader = ({ variables=false, type=FULL, ...props }) => {
currentPage, pageCount,
layout, setLayout,
typeFilter, setTypeFilter,
- conceptTypeCounts, conceptPages
+ conceptTypes, conceptPages
} = useHelxSearch()
const { analyticsEvents } = useAnalytics()
const { md } = useBreakpoint()
@@ -50,7 +50,7 @@ export const ResultsHeader = ({ variables=false, type=FULL, ...props }) => {
{ variables ? (
`${ variableStudyResultCount } studies and ${ totalVariableResults } variables`
) : (
- `${ totalConcepts } concepts (${ Object.keys(conceptPages).length } of ${ pageCount } pages)`
+ `${ totalConcepts } concepts`
) }
{ !variables && (
@@ -84,7 +84,7 @@ export const ResultsHeader = ({ variables=false, type=FULL, ...props }) => {
>
{
- Object.entries(conceptTypeCounts).sort((a, b) => b[1] - a[1]).map(([conceptType, count]) => (
+ Object.entries(conceptTypes).sort((a, b) => b[1] - a[1]).map(([conceptType, count]) => (
))
}
diff --git a/src/index.css b/src/index.css
index 5d845d72..39dd4549 100644
--- a/src/index.css
+++ b/src/index.css
@@ -7,6 +7,7 @@
body {
margin: 0;
font-family: 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
+ /* font-family: -apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol,noto color emoji; */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}