Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(search): add additional support for multi-faceted search #106

Merged
merged 8 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@hookform/resolvers": "2.0.0-beta.3",
"@reduxjs/toolkit": "^1.8.1",
"@sanity/ui": "^0.37.5",
"@sanity/uuid": "^3.0.1",
"@tanem/react-nprogress": "^5.0.0",
"copy-to-clipboard": "^3.3.1",
"date-fns": "^2.27.0",
Expand Down
6 changes: 3 additions & 3 deletions src/components/SearchFacet/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {CloseIcon} from '@sanity/icons'
import {Box, Flex, Label, Text} from '@sanity/ui'
import {SearchFacetInputProps} from '@types'
import {SearchFacetInputProps, WithId} from '@types'
import React, {ReactNode} from 'react'
import {useDispatch} from 'react-redux'
import styled from 'styled-components'
Expand All @@ -9,7 +9,7 @@ import {searchActions} from '../../modules/search'

type Props = {
children: ReactNode
facet: SearchFacetInputProps
facet: WithId<SearchFacetInputProps>
}

const Container = styled(Box)`
Expand All @@ -24,7 +24,7 @@ const SearchFacet = (props: Props) => {
const dispatch = useDispatch()

const handleClose = () => {
dispatch(searchActions.facetsRemove({facetName: facet.name}))
dispatch(searchActions.facetsRemoveById({facetId: facet.id}))
}

return (
Expand Down
11 changes: 6 additions & 5 deletions src/components/SearchFacetNumber/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {Box, Button, Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui'
import {
SearchFacetInputNumberModifier,
SearchFacetInputNumberProps,
SearchFacetOperatorType
SearchFacetOperatorType,
WithId
} from '@types'
import React from 'react'
import {useDispatch} from 'react-redux'
Expand All @@ -13,7 +14,7 @@ import SearchFacet from '../SearchFacet'
import TextInputNumber from '../TextInputNumber'

type Props = {
facet: SearchFacetInputNumberProps
facet: WithId<SearchFacetInputNumberProps>
}

const SearchFacetNumber = (props: Props) => {
Expand All @@ -28,15 +29,15 @@ const SearchFacetNumber = (props: Props) => {
: modifiers?.[0]

const handleOperatorItemClick = (operatorType: SearchFacetOperatorType) => {
dispatch(searchActions.facetsUpdate({name: facet.name, operatorType}))
dispatch(searchActions.facetsUpdateById({id: facet.id, operatorType}))
}

const handleModifierClick = (modifier: SearchFacetInputNumberModifier) => {
dispatch(searchActions.facetsUpdate({name: facet.name, modifier: modifier.name}))
dispatch(searchActions.facetsUpdateById({id: facet.id, modifier: modifier.name}))
}

const handleValueChange = (value: number) => {
dispatch(searchActions.facetsUpdate({name: facet.name, value}))
dispatch(searchActions.facetsUpdateById({id: facet.id, value}))
}

const selectedOperatorType: SearchFacetOperatorType = facet.operatorType ?? 'greaterThan'
Expand Down
5 changes: 3 additions & 2 deletions src/components/SearchFacetSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {Button, Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui'
import {
SearchFacetInputSelectListItemProps,
SearchFacetInputSelectProps,
SearchFacetOperatorType
SearchFacetOperatorType,
WithId
} from '@types'
import React from 'react'
import {useDispatch} from 'react-redux'
Expand All @@ -13,7 +14,7 @@ import {searchActions} from '../../modules/search'
import SearchFacet from '../SearchFacet'

type Props = {
facet: SearchFacetInputSelectProps
facet: WithId<SearchFacetInputSelectProps>
}

const SearchFacetSelect = (props: Props) => {
Expand Down
8 changes: 4 additions & 4 deletions src/components/SearchFacetString/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {SelectIcon} from '@sanity/icons'
import {Box, Button, Menu, MenuButton, MenuDivider, MenuItem, TextInput} from '@sanity/ui'
import {SearchFacetInputStringProps, SearchFacetOperatorType} from '@types'
import {SearchFacetInputStringProps, SearchFacetOperatorType, WithId} from '@types'
import React, {ChangeEvent} from 'react'
import {useDispatch} from 'react-redux'

Expand All @@ -9,7 +9,7 @@ import {searchActions} from '../../modules/search'
import SearchFacet from '../SearchFacet'

type Props = {
facet: SearchFacetInputStringProps
facet: WithId<SearchFacetInputStringProps>
}

const SearchFacetString = (props: Props) => {
Expand All @@ -19,11 +19,11 @@ const SearchFacetString = (props: Props) => {
const dispatch = useDispatch()

const handleOperatorItemClick = (operatorType: SearchFacetOperatorType) => {
dispatch(searchActions.facetsUpdate({name: facet.name, operatorType}))
dispatch(searchActions.facetsUpdateById({id: facet.id, operatorType}))
}

const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
dispatch(searchActions.facetsUpdate({name: facet.name, value: e.target.value}))
dispatch(searchActions.facetsUpdateById({id: facet.id, value: e.target.value}))
}

const selectedOperatorType: SearchFacetOperatorType = facet.operatorType
Expand Down
12 changes: 6 additions & 6 deletions src/components/SearchFacetTags/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {SelectIcon} from '@sanity/icons'
import {Box, Button, Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui'
import {ReactSelectOption, SearchFacetInputSearchableProps, SearchFacetOperatorType} from '@types'
import {ReactSelectOption, SearchFacetInputSearchableProps, SearchFacetOperatorType, WithId} from '@types'
import React from 'react'
import {useDispatch} from 'react-redux'
import Select from 'react-select'
Expand All @@ -13,7 +13,7 @@ import getTagSelectOptions from '../../utils/getTagSelectOptions'
import SearchFacet from '../SearchFacet'

type Props = {
facet: SearchFacetInputSearchableProps
facet: WithId<SearchFacetInputSearchableProps>
}

const SearchFacetTags = (props: Props) => {
Expand All @@ -27,17 +27,17 @@ const SearchFacetTags = (props: Props) => {

const handleChange = (option: ReactSelectOption) => {
dispatch(
searchActions.facetsUpdate({
name: facet.name,
searchActions.facetsUpdateById({
id: facet.id,
value: option
})
)
}

const handleOperatorItemClick = (operatorType: SearchFacetOperatorType) => {
dispatch(
searchActions.facetsUpdate({
name: facet.name,
searchActions.facetsUpdateById({
id: facet.id,
operatorType
})
)
Expand Down
9 changes: 5 additions & 4 deletions src/components/SearchFacets/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@ const SearchFacets = (props: Props) => {
const searchFacets = useTypedSelector(state => state.search.facets)

const Items = searchFacets.map(facet => {
const key = facet.id;
if (facet.type === 'number') {
return <SearchFacetNumber facet={facet} key={facet.name} />
return <SearchFacetNumber facet={facet} key={key} />
}

if (facet.type === 'searchable') {
return <SearchFacetTags facet={facet} key={facet.name} />
return <SearchFacetTags facet={facet} key={key} />
}

if (facet.type === 'select') {
return <SearchFacetSelect facet={facet} key={facet.name} />
return <SearchFacetSelect facet={facet} key={key} />
}

if (facet.type === 'string') {
return <SearchFacetString facet={facet} key={facet.name} />
return <SearchFacetString facet={facet} key={key} />
}

return null
Expand Down
11 changes: 4 additions & 7 deletions src/components/SearchFacetsControl/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ const SearchFacetsControl = () => {
return true
})

// Determine if there are any remaining un-selected facets
// (This operates under the assumption that only one of each facet can be active at any given time)
const hasRemainingSearchFacets =
filteredFacets.filter(facet => facet).length - searchFacets.length > 0
const hasSearchFacets = filteredFacets.length > 0

const renderMenuFacets = (
facets: (SearchFacetDivider | SearchFacetGroup | SearchFacetInputProps)[],
Expand All @@ -72,11 +69,11 @@ const SearchFacetsControl = () => {
}

if (facet) {
const isPresent = !!searchFacets.find(v => v.name === facet.name)
const disabled = !facet.operatorTypes && !!searchFacets.find(v => v.name === facet.name)
Copy link
Contributor Author

@nkgentile nkgentile Dec 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to generalize the facets that should only be used once (inUse, hasTransparency, etc.). Let me know if I should expand this logic.


return (
<MenuItem
disabled={isPresent}
disabled={disabled}
fontSize={1}
key={facet.name}
onClick={() => dispatch(searchActions.facetsAdd({facet}))}
Expand All @@ -98,7 +95,7 @@ const SearchFacetsControl = () => {
<MenuButton
button={
<Button
disabled={!hasRemainingSearchFacets}
disabled={!hasSearchFacets}
fontSize={1}
icon={AddCircleIcon}
mode="bleed"
Expand Down
7 changes: 3 additions & 4 deletions src/components/Tag/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {PANEL_HEIGHT} from '../../constants'
import useTypedSelector from '../../hooks/useTypedSelector'
import {selectAssetsPicked} from '../../modules/assets'
import {dialogActions} from '../../modules/dialog'
import {searchActions, selectHasSearchFacetTag, selectIsSearchFacetTag} from '../../modules/search'
import {searchActions, selectIsSearchFacetTag} from '../../modules/search'

type Props = {
actions?: TagActions[]
Expand Down Expand Up @@ -74,12 +74,11 @@ const Tag = (props: Props) => {
// Redux
const dispatch = useDispatch()
const assetsPicked = useTypedSelector(selectAssetsPicked)
const hasSearchFacetTag = useTypedSelector(selectHasSearchFacetTag)
const isSearchFacetTag = useTypedSelector(state => selectIsSearchFacetTag(state, tag?.tag?._id))

// Callbacks
const handleSearchFacetTagRemove = () => {
dispatch(searchActions.facetsRemove({facetName: 'tag'}))
dispatch(searchActions.facetsRemoveByTag({tagId: tag.tag._id}))
}

const handleShowAddTagToAssetsDialog = () => {
Expand Down Expand Up @@ -107,7 +106,7 @@ const Tag = (props: Props) => {
}
} as SearchFacetInputSearchableProps

if (hasSearchFacetTag) {
if (isSearchFacetTag) {
dispatch(
searchActions.facetsUpdate({
name: 'tag',
Expand Down
10 changes: 8 additions & 2 deletions src/modules/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,11 @@ export const assetsSearchEpic: MyEpic = action$ =>
ofType(
searchActions.facetsAdd.type,
searchActions.facetsClear.type,
searchActions.facetsRemove.type,
searchActions.facetsRemoveByName.type,
searchActions.facetsRemoveByTag.type,
searchActions.facetsRemoveById.type,
searchActions.facetsUpdate.type,
searchActions.facetsUpdateById.type,
searchActions.querySet.type
),
debounceTime(400),
Expand Down Expand Up @@ -725,8 +728,11 @@ export const assetsUnpickEpic: MyEpic = action$ =>
assetsActions.viewSet.type,
searchActions.facetsAdd.type,
searchActions.facetsClear.type,
searchActions.facetsRemove.type,
searchActions.facetsRemoveByName.type,
searchActions.facetsRemoveByTag.type,
searchActions.facetsRemoveById.type,
searchActions.facetsUpdate.type,
searchActions.facetsUpdateById.type,
searchActions.querySet.type
),
mergeMap(() => {
Expand Down
Loading