From 2d58016c1754025501d2314b48760784c477c81e Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Mon, 12 Dec 2022 14:49:54 -0800 Subject: [PATCH 1/8] fix: disable add filter button if no unused facets --- src/components/SearchFacetsControl/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SearchFacetsControl/index.tsx b/src/components/SearchFacetsControl/index.tsx index e2e045fd..2e5749a1 100644 --- a/src/components/SearchFacetsControl/index.tsx +++ b/src/components/SearchFacetsControl/index.tsx @@ -49,7 +49,7 @@ const SearchFacetsControl = () => { // 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 + filteredFacets.filter(facet => facet.type !== 'divider').length - searchFacets.length > 0 const renderMenuFacets = ( facets: (SearchFacetDivider | SearchFacetGroup | SearchFacetInputProps)[], From b45a3f63ecfd319ed7542cea68129cd415dc028f Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Mon, 12 Dec 2022 15:22:09 -0800 Subject: [PATCH 2/8] feat: adding a uuid to active facets --- package-lock.json | 27 ++++++++++++++++++++ package.json | 2 ++ src/components/SearchFacetsControl/index.tsx | 10 ++------ src/modules/search/index.ts | 5 ++-- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 01d2f711..77d45543 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "redux": "^4.0.5", "redux-observable": "^1.2.0", "rxjs": "^6.5.3", + "uuid": "^9.0.0", "yup": "^0.32.11" }, "devDependencies": { @@ -47,6 +48,7 @@ "@types/react-file-icon": "^1.0.1", "@types/react-redux": "^7.1.24", "@types/styled-components": "^5.1.7", + "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", "conventional-changelog-conventionalcommits": "^5.0.0", @@ -2210,6 +2212,12 @@ "version": "2.0.6", "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", + "dev": true + }, "node_modules/@types/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", @@ -11244,6 +11252,14 @@ "dev": true, "license": "MIT" }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "dev": true, @@ -13029,6 +13045,12 @@ "@types/unist": { "version": "2.0.6" }, + "@types/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", + "dev": true + }, "@types/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", @@ -19162,6 +19184,11 @@ "version": "1.0.2", "dev": true }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + }, "v8-compile-cache-lib": { "version": "3.0.1", "dev": true diff --git a/package.json b/package.json index fc169e75..091a44d7 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "redux": "^4.0.5", "redux-observable": "^1.2.0", "rxjs": "^6.5.3", + "uuid": "^9.0.0", "yup": "^0.32.11" }, "devDependencies": { @@ -77,6 +78,7 @@ "@types/react-file-icon": "^1.0.1", "@types/react-redux": "^7.1.24", "@types/styled-components": "^5.1.7", + "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", "conventional-changelog-conventionalcommits": "^5.0.0", diff --git a/src/components/SearchFacetsControl/index.tsx b/src/components/SearchFacetsControl/index.tsx index 2e5749a1..7849a194 100644 --- a/src/components/SearchFacetsControl/index.tsx +++ b/src/components/SearchFacetsControl/index.tsx @@ -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.type !== 'divider').length - searchFacets.length > 0 + const hasSearchFacets = filteredFacets.length > 0 const renderMenuFacets = ( facets: (SearchFacetDivider | SearchFacetGroup | SearchFacetInputProps)[], @@ -72,11 +69,8 @@ const SearchFacetsControl = () => { } if (facet) { - const isPresent = !!searchFacets.find(v => v.name === facet.name) - return ( dispatch(searchActions.facetsAdd({facet}))} @@ -98,7 +92,7 @@ const SearchFacetsControl = () => { ) { - state.facets.push(action.payload.facet) + state.facets.push({...action.payload.facet, id: uuid()}) }, // Clear all search facets facetsClear(state) { From fe9a3be9bcd6889ab78a9ec1933a7577773b935e Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Mon, 12 Dec 2022 16:06:11 -0800 Subject: [PATCH 3/8] feat: typing active search state --- src/components/SearchFacet/index.tsx | 6 +++--- src/components/SearchFacetNumber/index.tsx | 2 +- src/components/SearchFacetSelect/index.tsx | 2 +- src/components/SearchFacetString/index.tsx | 2 +- src/components/SearchFacetTags/index.tsx | 2 +- src/components/SearchFacets/index.tsx | 9 +++++---- src/components/Tag/index.tsx | 2 +- src/modules/assets/index.ts | 6 ++++-- src/modules/search/index.ts | 10 +++++++--- src/types/index.ts | 2 ++ 10 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/components/SearchFacet/index.tsx b/src/components/SearchFacet/index.tsx index 03bf2f4e..87ab8c09 100644 --- a/src/components/SearchFacet/index.tsx +++ b/src/components/SearchFacet/index.tsx @@ -1,6 +1,6 @@ import {CloseIcon} from '@sanity/icons' import {Box, Flex, Label, Text} from '@sanity/ui' -import {SearchFacetInputProps} from '@types' +import {SearchFacetActiveInputProps} from '@types' import React, {ReactNode} from 'react' import {useDispatch} from 'react-redux' import styled from 'styled-components' @@ -9,7 +9,7 @@ import {searchActions} from '../../modules/search' type Props = { children: ReactNode - facet: SearchFacetInputProps + facet: SearchFacetActiveInputProps } const Container = styled(Box)` @@ -24,7 +24,7 @@ const SearchFacet = (props: Props) => { const dispatch = useDispatch() const handleClose = () => { - dispatch(searchActions.facetsRemove({facetName: facet.name})) + dispatch(searchActions.facetRemoveById({facetId: facet.id})) } return ( diff --git a/src/components/SearchFacetNumber/index.tsx b/src/components/SearchFacetNumber/index.tsx index bee6334b..d9f7a275 100644 --- a/src/components/SearchFacetNumber/index.tsx +++ b/src/components/SearchFacetNumber/index.tsx @@ -13,7 +13,7 @@ import SearchFacet from '../SearchFacet' import TextInputNumber from '../TextInputNumber' type Props = { - facet: SearchFacetInputNumberProps + facet: SearchFacetInputNumberProps & {id:string} } const SearchFacetNumber = (props: Props) => { diff --git a/src/components/SearchFacetSelect/index.tsx b/src/components/SearchFacetSelect/index.tsx index 5242cb5e..c2db01eb 100644 --- a/src/components/SearchFacetSelect/index.tsx +++ b/src/components/SearchFacetSelect/index.tsx @@ -13,7 +13,7 @@ import {searchActions} from '../../modules/search' import SearchFacet from '../SearchFacet' type Props = { - facet: SearchFacetInputSelectProps + facet: SearchFacetInputSelectProps & {id:string} } const SearchFacetSelect = (props: Props) => { diff --git a/src/components/SearchFacetString/index.tsx b/src/components/SearchFacetString/index.tsx index 8c8bb0f9..2fe46d0a 100644 --- a/src/components/SearchFacetString/index.tsx +++ b/src/components/SearchFacetString/index.tsx @@ -9,7 +9,7 @@ import {searchActions} from '../../modules/search' import SearchFacet from '../SearchFacet' type Props = { - facet: SearchFacetInputStringProps + facet: SearchFacetInputStringProps & {id:string} } const SearchFacetString = (props: Props) => { diff --git a/src/components/SearchFacetTags/index.tsx b/src/components/SearchFacetTags/index.tsx index b5c2e0e3..548d5d83 100644 --- a/src/components/SearchFacetTags/index.tsx +++ b/src/components/SearchFacetTags/index.tsx @@ -13,7 +13,7 @@ import getTagSelectOptions from '../../utils/getTagSelectOptions' import SearchFacet from '../SearchFacet' type Props = { - facet: SearchFacetInputSearchableProps + facet: SearchFacetInputSearchableProps & {id:string} } const SearchFacetTags = (props: Props) => { diff --git a/src/components/SearchFacets/index.tsx b/src/components/SearchFacets/index.tsx index 19496264..7a47c497 100644 --- a/src/components/SearchFacets/index.tsx +++ b/src/components/SearchFacets/index.tsx @@ -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 + return } if (facet.type === 'searchable') { - return + return } if (facet.type === 'select') { - return + return } if (facet.type === 'string') { - return + return } return null diff --git a/src/components/Tag/index.tsx b/src/components/Tag/index.tsx index 9672a910..1ab88d52 100644 --- a/src/components/Tag/index.tsx +++ b/src/components/Tag/index.tsx @@ -79,7 +79,7 @@ const Tag = (props: Props) => { // Callbacks const handleSearchFacetTagRemove = () => { - dispatch(searchActions.facetsRemove({facetName: 'tag'})) + dispatch(searchActions.facetsRemoveByName({facetName: 'tag'})) } const handleShowAddTagToAssetsDialog = () => { diff --git a/src/modules/assets/index.ts b/src/modules/assets/index.ts index 091f428f..c03f79b9 100644 --- a/src/modules/assets/index.ts +++ b/src/modules/assets/index.ts @@ -577,7 +577,8 @@ export const assetsSearchEpic: MyEpic = action$ => ofType( searchActions.facetsAdd.type, searchActions.facetsClear.type, - searchActions.facetsRemove.type, + searchActions.facetsRemoveByName.type, + searchActions.facetRemoveById.type, searchActions.facetsUpdate.type, searchActions.querySet.type ), @@ -725,7 +726,8 @@ export const assetsUnpickEpic: MyEpic = action$ => assetsActions.viewSet.type, searchActions.facetsAdd.type, searchActions.facetsClear.type, - searchActions.facetsRemove.type, + searchActions.facetsRemoveByName.type, + searchActions.facetRemoveById.type, searchActions.facetsUpdate.type, searchActions.querySet.type ), diff --git a/src/modules/search/index.ts b/src/modules/search/index.ts index 9f25f7db..4f62ced0 100644 --- a/src/modules/search/index.ts +++ b/src/modules/search/index.ts @@ -1,5 +1,5 @@ import {AnyAction, PayloadAction, createSelector, createSlice} from '@reduxjs/toolkit' -import {SearchFacetInputProps, SearchFacetOperatorType} from '@types' +import {SearchFacetActiveInputProps, SearchFacetInputProps, SearchFacetOperatorType} from '@types' import {Epic} from 'redux-observable' import {Selector} from 'react-redux' import {empty, of} from 'rxjs' @@ -13,7 +13,7 @@ import {tagsActions} from '../tags' // (The main offender is `fieldModifier` which is currently a function) type SearchState = { - facets: (SearchFacetInputProps & {id: string})[] + facets: SearchFacetActiveInputProps[] query: string } @@ -35,9 +35,13 @@ const searchSlice = createSlice({ state.facets = [] }, // Remove search facet by name - facetsRemove(state, action: PayloadAction<{facetName: string}>) { + facetsRemoveByName(state, action: PayloadAction<{facetName: string}>) { state.facets = state.facets.filter(facet => facet.name !== action.payload.facetName) }, + // Remove search facet by name + facetRemoveById(state, action: PayloadAction<{facetId: string}>) { + state.facets = state.facets.filter(facet => facet.id !== action.payload.facetId) + }, // Update an existing search facet facetsUpdate( state, diff --git a/src/types/index.ts b/src/types/index.ts index 1c18f4e4..637bacb4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -165,6 +165,8 @@ export type SearchFacetInputProps = | SearchFacetInputSelectProps | SearchFacetInputStringProps +export type SearchFacetActiveInputProps = SearchFacetInputProps & {id: string} + export type SearchFacetDivider = { type: 'divider' } From ffd6de03d9126d9e369ebee66f17eac54684d5c5 Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Wed, 14 Dec 2022 16:14:02 -0800 Subject: [PATCH 4/8] feat: accounting for selected tag in sidebar --- src/components/SearchFacet/index.tsx | 2 +- src/components/SearchFacetNumber/index.tsx | 6 +- src/components/SearchFacetString/index.tsx | 4 +- src/components/SearchFacetTags/index.tsx | 8 +-- src/components/Tag/index.tsx | 7 +-- src/modules/assets/index.ts | 6 +- src/modules/search/index.ts | 73 ++++++++++++++-------- 7 files changed, 65 insertions(+), 41 deletions(-) diff --git a/src/components/SearchFacet/index.tsx b/src/components/SearchFacet/index.tsx index 87ab8c09..8c85e29a 100644 --- a/src/components/SearchFacet/index.tsx +++ b/src/components/SearchFacet/index.tsx @@ -24,7 +24,7 @@ const SearchFacet = (props: Props) => { const dispatch = useDispatch() const handleClose = () => { - dispatch(searchActions.facetRemoveById({facetId: facet.id})) + dispatch(searchActions.facetsRemoveById({facetId: facet.id})) } return ( diff --git a/src/components/SearchFacetNumber/index.tsx b/src/components/SearchFacetNumber/index.tsx index d9f7a275..e6d08d1f 100644 --- a/src/components/SearchFacetNumber/index.tsx +++ b/src/components/SearchFacetNumber/index.tsx @@ -28,15 +28,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' diff --git a/src/components/SearchFacetString/index.tsx b/src/components/SearchFacetString/index.tsx index 2fe46d0a..79a9f8ab 100644 --- a/src/components/SearchFacetString/index.tsx +++ b/src/components/SearchFacetString/index.tsx @@ -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) => { - 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 diff --git a/src/components/SearchFacetTags/index.tsx b/src/components/SearchFacetTags/index.tsx index 548d5d83..8b812a5f 100644 --- a/src/components/SearchFacetTags/index.tsx +++ b/src/components/SearchFacetTags/index.tsx @@ -27,8 +27,8 @@ const SearchFacetTags = (props: Props) => { const handleChange = (option: ReactSelectOption) => { dispatch( - searchActions.facetsUpdate({ - name: facet.name, + searchActions.facetsUpdateById({ + id: facet.id, value: option }) ) @@ -36,8 +36,8 @@ const SearchFacetTags = (props: Props) => { const handleOperatorItemClick = (operatorType: SearchFacetOperatorType) => { dispatch( - searchActions.facetsUpdate({ - name: facet.name, + searchActions.facetsUpdateById({ + id: facet.id, operatorType }) ) diff --git a/src/components/Tag/index.tsx b/src/components/Tag/index.tsx index 1ab88d52..5983328d 100644 --- a/src/components/Tag/index.tsx +++ b/src/components/Tag/index.tsx @@ -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[] @@ -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.facetsRemoveByName({facetName: 'tag'})) + dispatch(searchActions.facetsRemoveByTag({tagId: tag.tag._id})) } const handleShowAddTagToAssetsDialog = () => { @@ -107,7 +106,7 @@ const Tag = (props: Props) => { } } as SearchFacetInputSearchableProps - if (hasSearchFacetTag) { + if (isSearchFacetTag) { dispatch( searchActions.facetsUpdate({ name: 'tag', diff --git a/src/modules/assets/index.ts b/src/modules/assets/index.ts index c03f79b9..d7aed591 100644 --- a/src/modules/assets/index.ts +++ b/src/modules/assets/index.ts @@ -578,7 +578,8 @@ export const assetsSearchEpic: MyEpic = action$ => searchActions.facetsAdd.type, searchActions.facetsClear.type, searchActions.facetsRemoveByName.type, - searchActions.facetRemoveById.type, + searchActions.facetsRemoveByTag.type, + searchActions.facetsRemoveById.type, searchActions.facetsUpdate.type, searchActions.querySet.type ), @@ -727,7 +728,8 @@ export const assetsUnpickEpic: MyEpic = action$ => searchActions.facetsAdd.type, searchActions.facetsClear.type, searchActions.facetsRemoveByName.type, - searchActions.facetRemoveById.type, + searchActions.facetsRemoveByTag.type, + searchActions.facetsRemoveById.type, searchActions.facetsUpdate.type, searchActions.querySet.type ), diff --git a/src/modules/search/index.ts b/src/modules/search/index.ts index 4f62ced0..d8fc57dd 100644 --- a/src/modules/search/index.ts +++ b/src/modules/search/index.ts @@ -1,7 +1,6 @@ import {AnyAction, PayloadAction, createSelector, createSlice} from '@reduxjs/toolkit' import {SearchFacetActiveInputProps, SearchFacetInputProps, SearchFacetOperatorType} from '@types' import {Epic} from 'redux-observable' -import {Selector} from 'react-redux' import {empty, of} from 'rxjs' import {filter, mergeMap, withLatestFrom} from 'rxjs/operators' import {v4 as uuid} from 'uuid'; @@ -39,7 +38,16 @@ const searchSlice = createSlice({ state.facets = state.facets.filter(facet => facet.name !== action.payload.facetName) }, // Remove search facet by name - facetRemoveById(state, action: PayloadAction<{facetId: string}>) { + facetsRemoveByTag(state, action: PayloadAction<{tagId: string}>) { + state.facets = state.facets.filter(facet => + !(facet.name === 'tag' + && facet.type === 'searchable' + && (facet.operatorType === 'references' || facet.operatorType === 'doesNotReference') + && facet.value?.value === action.payload.tagId) + ) + }, + // Remove search facet by name + facetsRemoveById(state, action: PayloadAction<{facetId: string}>) { state.facets = state.facets.filter(facet => facet.id !== action.payload.facetId) }, // Update an existing search facet @@ -54,8 +62,38 @@ const searchSlice = createSlice({ ) { const {modifier, name, operatorType, value} = action.payload + const facet = state.facets.find((f) => f.name === name) + + if(!facet){ + return; + } + + if (facet.type === 'number' && modifier) { + facet.modifier = modifier + } + if (operatorType) { + facet.operatorType = operatorType + } + if (typeof value !== 'undefined') { + facet.value = value + } + + state.facets = state.facets.filter(f => f.name !== facet.name || f.id === facet.id) + }, + // Update an existing search facet + facetsUpdateById( + state, + action: PayloadAction<{ + modifier?: string + id: string + operatorType?: SearchFacetOperatorType + value?: any // TODO: type correctly + }> + ) { + const {modifier, id, operatorType, value} = action.payload + state.facets.forEach((facet, index) => { - if (facet.name === name) { + if (facet.id === id) { if (facet.type === 'number' && modifier) { facet.modifier = modifier } @@ -109,33 +147,18 @@ export const searchFacetTagUpdateEpic: MyEpic = (action$, state$) => ) // Selectors - -export const selectHasSearchFacetTag: Selector = createSelector( - (state: RootReducerState) => state.search.facets, - searchFacets => !!searchFacets?.find(facet => facet.name === 'tag') -) - export const selectIsSearchFacetTag = createSelector( [ - (state: RootReducerState) => state.tags.byIds, (state: RootReducerState) => state.search.facets, (_state: RootReducerState, tagId: string) => tagId ], - (tagsByIds, searchFacets, tagId) => { - const searchFacet = searchFacets?.find(facet => facet.name === 'tag') - - if (searchFacet?.type === 'searchable') { - const searchFacetTagId = searchFacet.value?.value - if (searchFacetTagId) { - return ( - tagsByIds[searchFacetTagId]?.tag?._id === tagId && - searchFacet?.operatorType === 'references' - ) - } - } - - return false - } + (searchFacets, tagId) => + searchFacets.some(facet => + facet.name === 'tag' + && facet.type === 'searchable' + && (facet.operatorType === 'references' || facet.operatorType === 'doesNotReference') + && facet.value?.value === tagId + ) ) export const searchActions = searchSlice.actions From 94bad9773b4024c35d40b3bf31494ec916a5998e Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Wed, 14 Dec 2022 16:39:30 -0800 Subject: [PATCH 5/8] feat: prevent reusing one-off facets --- src/components/SearchFacetsControl/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/SearchFacetsControl/index.tsx b/src/components/SearchFacetsControl/index.tsx index 7849a194..8138e33e 100644 --- a/src/components/SearchFacetsControl/index.tsx +++ b/src/components/SearchFacetsControl/index.tsx @@ -69,8 +69,11 @@ const SearchFacetsControl = () => { } if (facet) { + const disabled = !facet.operatorTypes && !!searchFacets.find(v => v.name === facet.name) + return ( dispatch(searchActions.facetsAdd({facet}))} From be0d2c7954f367ac33f4bdd31d1d9b699501a55e Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Wed, 14 Dec 2022 21:13:14 -0800 Subject: [PATCH 6/8] fix: adding update action to epic --- src/modules/assets/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/assets/index.ts b/src/modules/assets/index.ts index d7aed591..ccd85da8 100644 --- a/src/modules/assets/index.ts +++ b/src/modules/assets/index.ts @@ -581,6 +581,7 @@ export const assetsSearchEpic: MyEpic = action$ => searchActions.facetsRemoveByTag.type, searchActions.facetsRemoveById.type, searchActions.facetsUpdate.type, + searchActions.facetsUpdateById.type, searchActions.querySet.type ), debounceTime(400), @@ -731,6 +732,7 @@ export const assetsUnpickEpic: MyEpic = action$ => searchActions.facetsRemoveByTag.type, searchActions.facetsRemoveById.type, searchActions.facetsUpdate.type, + searchActions.facetsUpdateById.type, searchActions.querySet.type ), mergeMap(() => { From 8dfe94857ec2a588cf001f71830c2a0834229e78 Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Tue, 20 Dec 2022 11:25:49 -0800 Subject: [PATCH 7/8] chore: use `@sanity/uuid` --- package-lock.json | 47 ++++++++++++++++++++++++------------- package.json | 3 +-- src/modules/search/index.ts | 2 +- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 77d45543..e6f4ffa7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,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", @@ -29,7 +30,6 @@ "redux": "^4.0.5", "redux-observable": "^1.2.0", "rxjs": "^6.5.3", - "uuid": "^9.0.0", "yup": "^0.32.11" }, "devDependencies": { @@ -48,7 +48,6 @@ "@types/react-file-icon": "^1.0.1", "@types/react-redux": "^7.1.24", "@types/styled-components": "^5.1.7", - "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", "conventional-changelog-conventionalcommits": "^5.0.0", @@ -1640,6 +1639,15 @@ "node": ">= 4.0.0" } }, + "node_modules/@sanity/uuid": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sanity/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha512-cfWq8l/M6TiDYlp2VYJR2MNdrl0u/lkYWjJVflLHsiGjG8SZKbbRSsfG1fn7rSvdZg+o/xfBlKCfhFTtEiXKJg==", + "dependencies": { + "@types/uuid": "^8.0.0", + "uuid": "^8.0.0" + } + }, "node_modules/@sanity/validation": { "version": "2.34.0", "resolved": "https://registry.npmjs.org/@sanity/validation/-/validation-2.34.0.tgz", @@ -2213,10 +2221,9 @@ "license": "MIT" }, "node_modules/@types/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", - "dev": true + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, "node_modules/@types/warning": { "version": "3.0.0", @@ -11253,9 +11260,9 @@ "license": "MIT" }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { "uuid": "dist/bin/uuid" } @@ -12571,6 +12578,15 @@ } } }, + "@sanity/uuid": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sanity/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha512-cfWq8l/M6TiDYlp2VYJR2MNdrl0u/lkYWjJVflLHsiGjG8SZKbbRSsfG1fn7rSvdZg+o/xfBlKCfhFTtEiXKJg==", + "requires": { + "@types/uuid": "^8.0.0", + "uuid": "^8.0.0" + } + }, "@sanity/validation": { "version": "2.34.0", "resolved": "https://registry.npmjs.org/@sanity/validation/-/validation-2.34.0.tgz", @@ -13046,10 +13062,9 @@ "version": "2.0.6" }, "@types/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", - "dev": true + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, "@types/warning": { "version": "3.0.0", @@ -19185,9 +19200,9 @@ "dev": true }, "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache-lib": { "version": "3.0.1", diff --git a/package.json b/package.json index 091a44d7..53c05daf 100644 --- a/package.json +++ b/package.json @@ -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", @@ -59,7 +60,6 @@ "redux": "^4.0.5", "redux-observable": "^1.2.0", "rxjs": "^6.5.3", - "uuid": "^9.0.0", "yup": "^0.32.11" }, "devDependencies": { @@ -78,7 +78,6 @@ "@types/react-file-icon": "^1.0.1", "@types/react-redux": "^7.1.24", "@types/styled-components": "^5.1.7", - "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", "conventional-changelog-conventionalcommits": "^5.0.0", diff --git a/src/modules/search/index.ts b/src/modules/search/index.ts index d8fc57dd..b3089693 100644 --- a/src/modules/search/index.ts +++ b/src/modules/search/index.ts @@ -3,7 +3,7 @@ import {SearchFacetActiveInputProps, SearchFacetInputProps, SearchFacetOperatorT import {Epic} from 'redux-observable' import {empty, of} from 'rxjs' import {filter, mergeMap, withLatestFrom} from 'rxjs/operators' -import {v4 as uuid} from 'uuid'; +import {uuid} from '@sanity/uuid' import {RootReducerState} from '../types' import {tagsActions} from '../tags' From a5749b692653a3c09aa7275ea2dee181bc1d4537 Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Tue, 20 Dec 2022 11:30:23 -0800 Subject: [PATCH 8/8] refactor: prefer extending prop types with generic --- src/components/SearchFacet/index.tsx | 4 ++-- src/components/SearchFacetNumber/index.tsx | 5 +++-- src/components/SearchFacetSelect/index.tsx | 5 +++-- src/components/SearchFacetString/index.tsx | 4 ++-- src/components/SearchFacetTags/index.tsx | 4 ++-- src/modules/search/index.ts | 4 ++-- src/types/index.ts | 6 ++++-- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/components/SearchFacet/index.tsx b/src/components/SearchFacet/index.tsx index 8c85e29a..61316c57 100644 --- a/src/components/SearchFacet/index.tsx +++ b/src/components/SearchFacet/index.tsx @@ -1,6 +1,6 @@ import {CloseIcon} from '@sanity/icons' import {Box, Flex, Label, Text} from '@sanity/ui' -import {SearchFacetActiveInputProps} from '@types' +import {SearchFacetInputProps, WithId} from '@types' import React, {ReactNode} from 'react' import {useDispatch} from 'react-redux' import styled from 'styled-components' @@ -9,7 +9,7 @@ import {searchActions} from '../../modules/search' type Props = { children: ReactNode - facet: SearchFacetActiveInputProps + facet: WithId } const Container = styled(Box)` diff --git a/src/components/SearchFacetNumber/index.tsx b/src/components/SearchFacetNumber/index.tsx index e6d08d1f..b65d2d93 100644 --- a/src/components/SearchFacetNumber/index.tsx +++ b/src/components/SearchFacetNumber/index.tsx @@ -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' @@ -13,7 +14,7 @@ import SearchFacet from '../SearchFacet' import TextInputNumber from '../TextInputNumber' type Props = { - facet: SearchFacetInputNumberProps & {id:string} + facet: WithId } const SearchFacetNumber = (props: Props) => { diff --git a/src/components/SearchFacetSelect/index.tsx b/src/components/SearchFacetSelect/index.tsx index c2db01eb..b55f62ad 100644 --- a/src/components/SearchFacetSelect/index.tsx +++ b/src/components/SearchFacetSelect/index.tsx @@ -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' @@ -13,7 +14,7 @@ import {searchActions} from '../../modules/search' import SearchFacet from '../SearchFacet' type Props = { - facet: SearchFacetInputSelectProps & {id:string} + facet: WithId } const SearchFacetSelect = (props: Props) => { diff --git a/src/components/SearchFacetString/index.tsx b/src/components/SearchFacetString/index.tsx index 79a9f8ab..fcb4bf60 100644 --- a/src/components/SearchFacetString/index.tsx +++ b/src/components/SearchFacetString/index.tsx @@ -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' @@ -9,7 +9,7 @@ import {searchActions} from '../../modules/search' import SearchFacet from '../SearchFacet' type Props = { - facet: SearchFacetInputStringProps & {id:string} + facet: WithId } const SearchFacetString = (props: Props) => { diff --git a/src/components/SearchFacetTags/index.tsx b/src/components/SearchFacetTags/index.tsx index 8b812a5f..52f7d847 100644 --- a/src/components/SearchFacetTags/index.tsx +++ b/src/components/SearchFacetTags/index.tsx @@ -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' @@ -13,7 +13,7 @@ import getTagSelectOptions from '../../utils/getTagSelectOptions' import SearchFacet from '../SearchFacet' type Props = { - facet: SearchFacetInputSearchableProps & {id:string} + facet: WithId } const SearchFacetTags = (props: Props) => { diff --git a/src/modules/search/index.ts b/src/modules/search/index.ts index b3089693..c1b32b93 100644 --- a/src/modules/search/index.ts +++ b/src/modules/search/index.ts @@ -1,5 +1,5 @@ import {AnyAction, PayloadAction, createSelector, createSlice} from '@reduxjs/toolkit' -import {SearchFacetActiveInputProps, SearchFacetInputProps, SearchFacetOperatorType} from '@types' +import {SearchFacetInputProps, SearchFacetOperatorType, WithId} from '@types' import {Epic} from 'redux-observable' import {empty, of} from 'rxjs' import {filter, mergeMap, withLatestFrom} from 'rxjs/operators' @@ -12,7 +12,7 @@ import {tagsActions} from '../tags' // (The main offender is `fieldModifier` which is currently a function) type SearchState = { - facets: SearchFacetActiveInputProps[] + facets: WithId[] query: string } diff --git a/src/types/index.ts b/src/types/index.ts index 637bacb4..b6ecf46c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -165,8 +165,6 @@ export type SearchFacetInputProps = | SearchFacetInputSelectProps | SearchFacetInputStringProps -export type SearchFacetActiveInputProps = SearchFacetInputProps & {id: string} - export type SearchFacetDivider = { type: 'divider' } @@ -316,3 +314,7 @@ export type UploadItem = { size: number status: 'complete' | 'queued' | 'uploading' } + +export type WithId = T & { + id: string +} \ No newline at end of file