Skip to content

Commit

Permalink
Merge pull request #2779 from owid/gdocs-sane-search
Browse files Browse the repository at this point in the history
Better search on GDocs index page
  • Loading branch information
danyx23 authored Oct 18, 2023
2 parents 529c0b0 + 17b909a commit c7ddac6
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 52 deletions.
4 changes: 4 additions & 0 deletions adminSiteClient/GdocsIndexPage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
width: 100%;
}

.gdoc-index__help-link {
margin-right: 8px;
}

.gdoc-index-filter-checkbox {
cursor: pointer;
margin-right: 16px;
Expand Down
102 changes: 50 additions & 52 deletions adminSiteClient/GdocsIndexPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@ import {
faLightbulb,
faNewspaper,
faPuzzlePiece,
faQuestion,
} from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js"
import { Tag, OwidGdocInterface, OwidGdocType } from "@ourworldindata/utils"
import {
Tag,
OwidGdocInterface,
OwidGdocType,
SearchWord,
buildSearchWordsFromSearchString,
filterFunctionForSearchWords,
spansToUnformattedPlainText,
} from "@ourworldindata/utils"
import { Route, RouteComponentProps } from "react-router-dom"
import { Link } from "./Link.js"
import { GdocsAdd } from "./GdocsAdd.js"
import { observer } from "mobx-react"
import { GdocsStoreContext } from "./GdocsStore.js"
import { computed, observable } from "mobx"
import { BAKED_BASE_URL } from "../settings/clientSettings.js"
import fuzzysort from "fuzzysort"
import { GdocsEditLink } from "./GdocsEditLink.js"

const iconGdocTypeMap = {
Expand All @@ -27,11 +35,6 @@ const iconGdocTypeMap = {
[OwidGdocType.TopicPage]: <FontAwesomeIcon icon={faLightbulb} />,
}

interface Searchable {
gdoc: OwidGdocInterface
term?: Fuzzysort.Prepared
}

@observer
class GdocsIndexPageSearch extends React.Component<{
filters: Record<OwidGdocType, boolean>
Expand Down Expand Up @@ -106,6 +109,11 @@ export class GdocsIndexPage extends React.Component<GdocsMatchProps> {

@observable search = { value: "" }

@computed get searchWords(): SearchWord[] {
const { search } = this
return buildSearchWordsFromSearchString(search.value)
}

async componentDidMount(): Promise<void> {
await this.context?.fetchTags()
await this.context?.fetchGdocs()
Expand All @@ -116,27 +124,10 @@ export class GdocsIndexPage extends React.Component<GdocsMatchProps> {
return this.context?.availableTags || []
}

@computed get searchIndex(): Searchable[] {
if (!this.context) return []
const searchIndex: Searchable[] = []
for (const gdoc of this.context.gdocs) {
searchIndex.push({
gdoc,
term: fuzzysort.prepare(
`${gdoc.content.title} ${gdoc.content.authors?.join(
" "
)} ${gdoc.tags?.map(({ name }) => name).join(" ")}`
),
})
}

return searchIndex
}

@computed
get visibleGdocs(): OwidGdocInterface[] {
const { context, search, searchIndex } = this
@computed get allGdocsToShow(): OwidGdocInterface[] {
const { searchWords, context } = this
if (!context) return []

// Don't filter unless at least one filter is active
const shouldUseFilters = !!Object.values(this.filters).find(
(isFilterActive) => isFilterActive
Expand All @@ -149,31 +140,29 @@ export class GdocsIndexPage extends React.Component<GdocsMatchProps> {
!gdoc.content.type || !!this.filters[gdoc.content.type]
)
: context.gdocs
if (!search.value) return filteredByType

const fuzzysorted = fuzzysort.go(search.value, searchIndex, {
limit: 50,
key: "term",
})

const uniqueFiltered = fuzzysorted.reduce(
(acc: Set<OwidGdocInterface>, { obj: { gdoc } }) => {
const shouldInclude =
// Don't filter unless at least one filter is active
!shouldUseFilters ||
!gdoc.content.type ||
this.filters[gdoc.content.type]

if (shouldInclude) {
acc.add(gdoc)
}

return acc
},
new Set<OwidGdocInterface>()
)

return [...uniqueFiltered]
if (searchWords.length > 0) {
const filterFn = filterFunctionForSearchWords(
searchWords,
(gdoc: OwidGdocInterface) => [
gdoc.content.title,
gdoc.content.subtitle,
gdoc.content.summary
? spansToUnformattedPlainText(
gdoc.content.summary.flatMap(
(block) => block.value
)
)
: undefined,
gdoc.slug,
gdoc.content.authors?.join(" "),
gdoc.tags?.map(({ name }) => name).join(" "),
]
)
return filteredByType.filter(filterFn)
} else {
return filteredByType
}
}

render() {
Expand All @@ -186,6 +175,15 @@ export class GdocsIndexPage extends React.Component<GdocsMatchProps> {
search={this.search}
/>
<div>
<a
className="btn btn-secondary gdoc-index__help-link"
target="_blank"
href="https://docs.google.com/document/d/1OLoTWloy4VecOjKTjB1wLV6tEphHJIMXfexrf1ZYJzU/edit"
rel="noopener"
>
<FontAwesomeIcon icon={faQuestion} /> Open
documentation
</a>
<button
className="btn btn-primary"
onClick={() =>
Expand All @@ -200,7 +198,7 @@ export class GdocsIndexPage extends React.Component<GdocsMatchProps> {
</div>
</div>

{this.visibleGdocs.map((gdoc) => (
{this.allGdocsToShow.map((gdoc) => (
<div
key={gdoc.id}
className={cx(`gdoc-index-item`, {
Expand Down

0 comments on commit c7ddac6

Please sign in to comment.