Enrich filters with all types (#2653)
This commit is contained in:
@ -20,7 +20,7 @@ export const KeyboardShortcutMenu = () => {
|
|||||||
isKeyboardShortcutMenuOpenedState,
|
isKeyboardShortcutMenuOpenedState,
|
||||||
);
|
);
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
'shift+?,meta+?,esc',
|
'shift+?,meta+?',
|
||||||
() => {
|
() => {
|
||||||
toggleKeyboardShortcutMenu();
|
toggleKeyboardShortcutMenu();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -12,14 +12,29 @@ export const formatFieldMetadataItemsAsFilterDefinitions = ({
|
|||||||
if (
|
if (
|
||||||
![
|
![
|
||||||
FieldMetadataType.DateTime,
|
FieldMetadataType.DateTime,
|
||||||
FieldMetadataType.Number,
|
|
||||||
FieldMetadataType.Currency,
|
|
||||||
FieldMetadataType.Text,
|
FieldMetadataType.Text,
|
||||||
].includes(field.type) ||
|
FieldMetadataType.Email,
|
||||||
field.name === 'probability'
|
FieldMetadataType.Number,
|
||||||
|
FieldMetadataType.Link,
|
||||||
|
FieldMetadataType.FullName,
|
||||||
|
FieldMetadataType.Relation,
|
||||||
|
FieldMetadataType.Currency,
|
||||||
|
].includes(field.type)
|
||||||
) {
|
) {
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Todo: remove once Rating fieldtype is implemented
|
||||||
|
if (field.name === 'probability') {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.type === FieldMetadataType.Relation) {
|
||||||
|
if (field.fromRelationMetadata) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [...acc, formatFieldMetadataItemAsFilterDefinition({ field })];
|
return [...acc, formatFieldMetadataItemAsFilterDefinition({ field })];
|
||||||
}, [] as FilterDefinition[]);
|
}, [] as FilterDefinition[]);
|
||||||
|
|
||||||
@ -34,9 +49,19 @@ const formatFieldMetadataItemAsFilterDefinition = ({
|
|||||||
type:
|
type:
|
||||||
field.type === FieldMetadataType.DateTime
|
field.type === FieldMetadataType.DateTime
|
||||||
? 'DATE_TIME'
|
? 'DATE_TIME'
|
||||||
|
: field.type === FieldMetadataType.Link
|
||||||
|
? 'LINK'
|
||||||
|
: field.type === FieldMetadataType.FullName
|
||||||
|
? 'FULL_NAME'
|
||||||
: field.type === FieldMetadataType.Number
|
: field.type === FieldMetadataType.Number
|
||||||
? 'NUMBER'
|
? 'NUMBER'
|
||||||
: field.type === FieldMetadataType.Currency
|
: field.type === FieldMetadataType.Currency
|
||||||
? 'CURRENCY'
|
? 'CURRENCY'
|
||||||
|
: field.type === FieldMetadataType.Email
|
||||||
|
? 'TEXT'
|
||||||
|
: field.type === FieldMetadataType.Phone
|
||||||
|
? 'TEXT'
|
||||||
|
: field.type === FieldMetadataType.Relation
|
||||||
|
? 'RELATION'
|
||||||
: 'TEXT',
|
: 'TEXT',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,16 +4,16 @@ import { useQuery } from '@apollo/client';
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||||
import { IconUserCircle } from '@/ui/display/icon';
|
import { IconUserCircle } from '@/ui/display/icon';
|
||||||
|
import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker';
|
||||||
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
|
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
|
||||||
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
|
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||||
import { useRelationField } from '@/ui/object/field/meta-types/hooks/useRelationField';
|
|
||||||
import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition';
|
import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition';
|
||||||
import { FieldRelationMetadata } from '@/ui/object/field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/ui/object/field/types/FieldMetadata';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
|
||||||
export type RelationPickerProps = {
|
export type RelationPickerProps = {
|
||||||
recordId: string;
|
recordId?: string;
|
||||||
onSubmit: (newUser: EntityForSelect | null) => void;
|
onSubmit: (newUser: EntityForSelect | null) => void;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
width?: number;
|
width?: number;
|
||||||
@ -43,9 +43,9 @@ export const RelationPicker = ({
|
|||||||
|
|
||||||
const useFindManyQuery = (options: any) => useQuery(findManyQuery, options);
|
const useFindManyQuery = (options: any) => useQuery(findManyQuery, options);
|
||||||
|
|
||||||
const { identifiersMapper, searchQuery } = useRelationField();
|
const { identifiersMapper, searchQuery } = useRelationPicker();
|
||||||
|
|
||||||
const workspaceMembers = useFilteredSearchEntityQuery({
|
const records = useFilteredSearchEntityQuery({
|
||||||
queryHook: useFindManyQuery,
|
queryHook: useFindManyQuery,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
@ -74,11 +74,11 @@ export const RelationPicker = ({
|
|||||||
<SingleEntitySelect
|
<SingleEntitySelect
|
||||||
EmptyIcon={IconUserCircle}
|
EmptyIcon={IconUserCircle}
|
||||||
emptyLabel="No Owner"
|
emptyLabel="No Owner"
|
||||||
entitiesToSelect={workspaceMembers.entitiesToSelect}
|
entitiesToSelect={records.entitiesToSelect}
|
||||||
loading={workspaceMembers.loading}
|
loading={records.loading}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onEntitySelected={handleEntitySelected}
|
onEntitySelected={handleEntitySelected}
|
||||||
selectedEntity={workspaceMembers.selectedEntities[0]}
|
selectedEntity={records.selectedEntities[0]}
|
||||||
width={width}
|
width={width}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -1,11 +1,12 @@
|
|||||||
import { EntityChip } from '@/ui/display/chip/components/EntityChip';
|
import { EntityChip } from '@/ui/display/chip/components/EntityChip';
|
||||||
|
import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker';
|
||||||
|
|
||||||
import { useRelationField } from '../../hooks/useRelationField';
|
import { useRelationField } from '../../hooks/useRelationField';
|
||||||
|
|
||||||
export const RelationFieldDisplay = () => {
|
export const RelationFieldDisplay = () => {
|
||||||
const { fieldValue, fieldDefinition } = useRelationField();
|
const { fieldValue, fieldDefinition } = useRelationField();
|
||||||
|
|
||||||
const { identifiersMapper } = useRelationField();
|
const { identifiersMapper } = useRelationPicker();
|
||||||
|
|
||||||
if (!fieldValue || !fieldDefinition || !identifiersMapper) {
|
if (!fieldValue || !fieldDefinition || !identifiersMapper) {
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker';
|
|
||||||
|
|
||||||
import { FieldContext } from '../../contexts/FieldContext';
|
import { FieldContext } from '../../contexts/FieldContext';
|
||||||
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
|
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
|
||||||
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
||||||
@ -32,15 +30,11 @@ export const useRelationField = () => {
|
|||||||
|
|
||||||
const initialValue = fieldInitialValue?.isEmpty ? null : fieldValue;
|
const initialValue = fieldInitialValue?.isEmpty ? null : fieldValue;
|
||||||
|
|
||||||
const { identifiersMapper, searchQuery } = useRelationPicker();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
fieldValue,
|
fieldValue,
|
||||||
initialValue,
|
initialValue,
|
||||||
initialSearchValue,
|
initialSearchValue,
|
||||||
setFieldValue,
|
setFieldValue,
|
||||||
searchQuery,
|
|
||||||
identifiersMapper,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { RelationPicker } from '@/ui/input/components/internal/relation-picker/RelationPicker';
|
import { RelationPicker } from '@/ui/input/components/internal/relation-picker/components/RelationPicker';
|
||||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||||
|
|
||||||
import { usePersistField } from '../../../hooks/usePersistField';
|
import { usePersistField } from '../../../hooks/usePersistField';
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||||
|
import { useFilter } from '@/ui/object/object-filter-dropdown/hooks/useFilter';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
import { ObjectFilterDropdownId } from '../constants/ObjectFilterDropdownId';
|
import { ObjectFilterDropdownId } from '../constants/ObjectFilterDropdownId';
|
||||||
@ -14,9 +15,12 @@ type MultipleFiltersDropdownButtonProps = {
|
|||||||
export const MultipleFiltersDropdownButton = ({
|
export const MultipleFiltersDropdownButton = ({
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: MultipleFiltersDropdownButtonProps) => {
|
}: MultipleFiltersDropdownButtonProps) => {
|
||||||
|
const { resetFilter } = useFilter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownScope dropdownScopeId={ObjectFilterDropdownId}>
|
<DropdownScope dropdownScopeId={ObjectFilterDropdownId}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
onClose={resetFilter}
|
||||||
clickableComponent={<MultipleFiltersButton />}
|
clickableComponent={<MultipleFiltersButton />}
|
||||||
dropdownComponents={<MultipleFiltersDropdownContent />}
|
dropdownComponents={<MultipleFiltersDropdownContent />}
|
||||||
dropdownHotkeyScope={hotkeyScope}
|
dropdownHotkeyScope={hotkeyScope}
|
||||||
|
|||||||
@ -30,19 +30,19 @@ export const MultipleFiltersDropdownContent = () => {
|
|||||||
<>
|
<>
|
||||||
<ObjectFilterDropdownOperandButton />
|
<ObjectFilterDropdownOperandButton />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
{filterDefinitionUsedInDropdown.type === 'TEXT' && (
|
{['TEXT', 'EMAIL', 'PHONE', 'FULL_NAME', 'LINK'].includes(
|
||||||
<ObjectFilterDropdownTextSearchInput />
|
filterDefinitionUsedInDropdown.type,
|
||||||
)}
|
) && <ObjectFilterDropdownTextSearchInput />}
|
||||||
{['NUMBER', 'CURRENCY'].includes(
|
{['NUMBER', 'CURRENCY'].includes(
|
||||||
filterDefinitionUsedInDropdown.type,
|
filterDefinitionUsedInDropdown.type,
|
||||||
) && <ObjectFilterDropdownNumberSearchInput />}
|
) && <ObjectFilterDropdownNumberSearchInput />}
|
||||||
{filterDefinitionUsedInDropdown.type === 'DATE_TIME' && (
|
{filterDefinitionUsedInDropdown.type === 'DATE_TIME' && (
|
||||||
<ObjectFilterDropdownDateSearchInput />
|
<ObjectFilterDropdownDateSearchInput />
|
||||||
)}
|
)}
|
||||||
{filterDefinitionUsedInDropdown.type === 'ENTITY' && (
|
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
|
||||||
<ObjectFilterDropdownEntitySearchInput />
|
<ObjectFilterDropdownEntitySearchInput />
|
||||||
)}
|
)}
|
||||||
{filterDefinitionUsedInDropdown.type === 'ENTITY' && (
|
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
|
||||||
<ObjectFilterDropdownEntitySelect />
|
<ObjectFilterDropdownEntitySelect />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export const ObjectFilterDropdownButton = ({
|
|||||||
|
|
||||||
const hasOnlyOneEntityFilter =
|
const hasOnlyOneEntityFilter =
|
||||||
availableFilterDefinitions.length === 1 &&
|
availableFilterDefinitions.length === 1 &&
|
||||||
availableFilterDefinitions[0].type === 'ENTITY';
|
availableFilterDefinitions[0].type === 'RELATION';
|
||||||
|
|
||||||
if (!availableFilterDefinitions.length) {
|
if (!availableFilterDefinitions.length) {
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
|
import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
|
||||||
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
|
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
|
||||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||||
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
|
||||||
import { useFilter } from '../hooks/useFilter';
|
import { useFilter } from '../hooks/useFilter';
|
||||||
@ -21,9 +22,11 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
selectFilter,
|
selectFilter,
|
||||||
} = useFilter();
|
} = useFilter();
|
||||||
|
|
||||||
|
const { closeDropdown } = useDropdown();
|
||||||
|
|
||||||
const [isAllEntitySelected, setIsAllEntitySelected] = useState(false);
|
const [isAllEntitySelected, setIsAllEntitySelected] = useState(false);
|
||||||
|
|
||||||
const handleUserSelected = (
|
const handleRecordSelected = (
|
||||||
selectedEntity: EntityForSelect | null | undefined,
|
selectedEntity: EntityForSelect | null | undefined,
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
@ -39,6 +42,7 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setObjectFilterDropdownSelectedEntityId(selectedEntity.id);
|
setObjectFilterDropdownSelectedEntityId(selectedEntity.id);
|
||||||
|
closeDropdown();
|
||||||
|
|
||||||
selectFilter?.({
|
selectFilter?.({
|
||||||
displayValue: selectedEntity.name,
|
displayValue: selectedEntity.name,
|
||||||
@ -69,6 +73,7 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
|
|
||||||
setIsAllEntitySelected(true);
|
setIsAllEntitySelected(true);
|
||||||
setObjectFilterDropdownSelectedEntityId(null);
|
setObjectFilterDropdownSelectedEntityId(null);
|
||||||
|
closeDropdown();
|
||||||
|
|
||||||
selectFilter?.({
|
selectFilter?.({
|
||||||
displayValue: filterDefinitionUsedInDropdown.selectAllLabel,
|
displayValue: filterDefinitionUsedInDropdown.selectAllLabel,
|
||||||
@ -100,7 +105,7 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
entitiesToSelect={entitiesForSelect.entitiesToSelect}
|
entitiesToSelect={entitiesForSelect.entitiesToSelect}
|
||||||
selectedEntity={entitiesForSelect.selectedEntities[0]}
|
selectedEntity={entitiesForSelect.selectedEntities[0]}
|
||||||
loading={entitiesForSelect.loading}
|
loading={entitiesForSelect.loading}
|
||||||
onEntitySelected={handleUserSelected}
|
onEntitySelected={handleRecordSelected}
|
||||||
SelectAllIcon={filterDefinitionUsedInDropdown?.SelectAllIcon}
|
SelectAllIcon={filterDefinitionUsedInDropdown?.SelectAllIcon}
|
||||||
selectAllLabel={filterDefinitionUsedInDropdown?.selectAllLabel}
|
selectAllLabel={filterDefinitionUsedInDropdown?.selectAllLabel}
|
||||||
isAllEntitySelected={isAllEntitySelected}
|
isAllEntitySelected={isAllEntitySelected}
|
||||||
|
|||||||
@ -1,21 +1,52 @@
|
|||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { useQuery } from '@apollo/client';
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||||
|
import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker';
|
||||||
|
import { ObjectFilterDropdownEntitySearchSelect } from '@/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect';
|
||||||
|
|
||||||
import { useFilter } from '../hooks/useFilter';
|
import { useFilter } from '../hooks/useFilter';
|
||||||
|
|
||||||
export const ObjectFilterDropdownEntitySelect = () => {
|
export const ObjectFilterDropdownEntitySelect = () => {
|
||||||
const { filterDefinitionUsedInDropdown } = useFilter();
|
const {
|
||||||
|
filterDefinitionUsedInDropdown,
|
||||||
|
objectFilterDropdownSearchInput,
|
||||||
|
objectFilterDropdownSelectedEntityId,
|
||||||
|
} = useFilter();
|
||||||
|
|
||||||
if (filterDefinitionUsedInDropdown?.type !== 'ENTITY') {
|
const { findManyQuery } = useObjectMetadataItem({
|
||||||
|
objectNameSingular: 'company',
|
||||||
|
});
|
||||||
|
|
||||||
|
const useFindManyQuery = (options: any) => useQuery(findManyQuery, options);
|
||||||
|
|
||||||
|
const { identifiersMapper, searchQuery } = useRelationPicker();
|
||||||
|
|
||||||
|
const filteredSearchEntityResults = useFilteredSearchEntityQuery({
|
||||||
|
queryHook: useFindManyQuery,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
fieldNames: searchQuery?.computeFilterFields?.('company') ?? [],
|
||||||
|
filter: objectFilterDropdownSearchInput,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
orderByField: 'createdAt',
|
||||||
|
selectedIds: objectFilterDropdownSelectedEntityId
|
||||||
|
? [objectFilterDropdownSelectedEntityId]
|
||||||
|
: [],
|
||||||
|
mappingFunction: (record: any) => identifiersMapper?.(record, 'company'),
|
||||||
|
objectNamePlural: 'companies',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filterDefinitionUsedInDropdown?.type !== 'RELATION') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
<ObjectFilterDropdownEntitySearchSelect
|
||||||
<RecoilScope>
|
entitiesForSelect={filteredSearchEntityResults}
|
||||||
{filterDefinitionUsedInDropdown.entitySelectComponent}
|
/>
|
||||||
</RecoilScope>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,27 +21,29 @@ export const ObjectFilterDropdownFilterSelect = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{availableFilterDefinitions.map((availableFilterDefinition, index) => (
|
{[...availableFilterDefinitions]
|
||||||
<MenuItem
|
.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
key={`select-filter-${index}`}
|
.map((availableFilterDefinition, index) => (
|
||||||
testId={`select-filter-${index}`}
|
<MenuItem
|
||||||
onClick={() => {
|
key={`select-filter-${index}`}
|
||||||
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
testId={`select-filter-${index}`}
|
||||||
|
onClick={() => {
|
||||||
|
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
||||||
|
|
||||||
if (availableFilterDefinition.type === 'ENTITY') {
|
if (availableFilterDefinition.type === 'RELATION') {
|
||||||
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOperandInDropdown(
|
setSelectedOperandInDropdown(
|
||||||
getOperandsForFilterType(availableFilterDefinition.type)?.[0],
|
getOperandsForFilterType(availableFilterDefinition.type)?.[0],
|
||||||
);
|
);
|
||||||
|
|
||||||
setObjectFilterDropdownSearchInput('');
|
setObjectFilterDropdownSearchInput('');
|
||||||
}}
|
}}
|
||||||
LeftIcon={icons[availableFilterDefinition.iconName]}
|
LeftIcon={icons[availableFilterDefinition.iconName]}
|
||||||
text={availableFilterDefinition.label}
|
text={availableFilterDefinition.label}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export const SingleEntityObjectFilterDropdownButton = ({
|
|||||||
selectedFilter,
|
selectedFilter,
|
||||||
setFilterDefinitionUsedInDropdown,
|
setFilterDefinitionUsedInDropdown,
|
||||||
setSelectedOperandInDropdown,
|
setSelectedOperandInDropdown,
|
||||||
|
resetFilter,
|
||||||
} = useFilter();
|
} = useFilter();
|
||||||
|
|
||||||
const availableFilter = availableFilterDefinitions[0];
|
const availableFilter = availableFilterDefinitions[0];
|
||||||
|
|||||||
@ -48,6 +48,18 @@ export const useFilter = (props?: UseFilterProps) => {
|
|||||||
[setSelectedFilter, onFilterSelect],
|
[setSelectedFilter, onFilterSelect],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const resetFilter = useCallback(() => {
|
||||||
|
setObjectFilterDropdownSearchInput('');
|
||||||
|
setObjectFilterDropdownSelectedEntityId(null);
|
||||||
|
setSelectedFilter(undefined);
|
||||||
|
setSelectedOperandInDropdown(null);
|
||||||
|
}, [
|
||||||
|
setObjectFilterDropdownSearchInput,
|
||||||
|
setObjectFilterDropdownSelectedEntityId,
|
||||||
|
setSelectedFilter,
|
||||||
|
setSelectedOperandInDropdown,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scopeId,
|
scopeId,
|
||||||
availableFilterDefinitions,
|
availableFilterDefinitions,
|
||||||
@ -67,5 +79,6 @@ export const useFilter = (props?: UseFilterProps) => {
|
|||||||
selectedOperandInDropdown,
|
selectedOperandInDropdown,
|
||||||
setSelectedOperandInDropdown,
|
setSelectedOperandInDropdown,
|
||||||
selectFilter,
|
selectFilter,
|
||||||
|
resetFilter,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
export type FilterType =
|
export type FilterType =
|
||||||
| 'TEXT'
|
| 'TEXT'
|
||||||
|
| 'PHONE'
|
||||||
|
| 'EMAIL'
|
||||||
| 'DATE_TIME'
|
| 'DATE_TIME'
|
||||||
| 'ENTITY'
|
|
||||||
| 'NUMBER'
|
| 'NUMBER'
|
||||||
| 'CURRENCY';
|
| 'CURRENCY'
|
||||||
|
| 'FULL_NAME'
|
||||||
|
| 'LINK'
|
||||||
|
| 'RELATION';
|
||||||
|
|||||||
@ -7,12 +7,15 @@ export const getOperandsForFilterType = (
|
|||||||
): ViewFilterOperand[] => {
|
): ViewFilterOperand[] => {
|
||||||
switch (filterType) {
|
switch (filterType) {
|
||||||
case 'TEXT':
|
case 'TEXT':
|
||||||
|
case 'EMAIL':
|
||||||
|
case 'FULL_NAME':
|
||||||
|
case 'LINK':
|
||||||
return [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain];
|
return [ViewFilterOperand.Contains, ViewFilterOperand.DoesNotContain];
|
||||||
case 'CURRENCY':
|
case 'CURRENCY':
|
||||||
case 'NUMBER':
|
case 'NUMBER':
|
||||||
case 'DATE_TIME':
|
case 'DATE_TIME':
|
||||||
return [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan];
|
return [ViewFilterOperand.GreaterThan, ViewFilterOperand.LessThan];
|
||||||
case 'ENTITY':
|
case 'RELATION':
|
||||||
return [ViewFilterOperand.Is, ViewFilterOperand.IsNot];
|
return [ViewFilterOperand.Is, ViewFilterOperand.IsNot];
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export const turnFiltersIntoWhereClauseV2 = (
|
|||||||
filters: FilterToTurnIntoWhereClause[],
|
filters: FilterToTurnIntoWhereClause[],
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
fields: Pick<Field, 'id' | 'name'>[],
|
||||||
) => {
|
) => {
|
||||||
const whereClause: Record<string, any> = {};
|
const whereClause: any[] = [];
|
||||||
|
|
||||||
filters.forEach((filter) => {
|
filters.forEach((filter) => {
|
||||||
const correspondingField = fields.find(
|
const correspondingField = fields.find(
|
||||||
@ -26,53 +26,25 @@ export const turnFiltersIntoWhereClauseV2 = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (filter.definition.type) {
|
switch (filter.definition.type) {
|
||||||
|
case 'EMAIL':
|
||||||
|
case 'PHONE':
|
||||||
case 'TEXT':
|
case 'TEXT':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case ViewFilterOperand.Contains:
|
case ViewFilterOperand.Contains:
|
||||||
whereClause[correspondingField.name] = {
|
whereClause.push({
|
||||||
eq: filter.value,
|
[correspondingField.name]: {
|
||||||
};
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
case ViewFilterOperand.DoesNotContain:
|
case ViewFilterOperand.DoesNotContain:
|
||||||
whereClause[correspondingField.name] = {
|
whereClause.push({
|
||||||
not: {
|
not: {
|
||||||
eq: filter.value,
|
[correspondingField.name]: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
return;
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'NUMBER':
|
|
||||||
switch (filter.operand) {
|
|
||||||
case ViewFilterOperand.GreaterThan:
|
|
||||||
whereClause[correspondingField.name] = {
|
|
||||||
gte: parseFloat(filter.value),
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
case ViewFilterOperand.LessThan:
|
|
||||||
whereClause[correspondingField.name] = {
|
|
||||||
lte: parseFloat(filter.value),
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'CURRENCY':
|
|
||||||
switch (filter.operand) {
|
|
||||||
case ViewFilterOperand.GreaterThan:
|
|
||||||
whereClause[correspondingField.name] = {
|
|
||||||
amountMicros: { gte: parseFloat(filter.value) * 1000000 },
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
case ViewFilterOperand.LessThan:
|
|
||||||
whereClause[correspondingField.name] = {
|
|
||||||
amountMicros: { lte: parseFloat(filter.value) * 1000000 },
|
|
||||||
};
|
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -82,14 +54,159 @@ export const turnFiltersIntoWhereClauseV2 = (
|
|||||||
case 'DATE_TIME':
|
case 'DATE_TIME':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case ViewFilterOperand.GreaterThan:
|
case ViewFilterOperand.GreaterThan:
|
||||||
whereClause[correspondingField.name] = {
|
whereClause.push({
|
||||||
gte: filter.value,
|
[correspondingField.name]: {
|
||||||
};
|
gte: filter.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
case ViewFilterOperand.LessThan:
|
case ViewFilterOperand.LessThan:
|
||||||
whereClause[correspondingField.name] = {
|
whereClause.push({
|
||||||
lte: filter.value,
|
[correspondingField.name]: {
|
||||||
};
|
lte: filter.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'NUMBER':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case ViewFilterOperand.GreaterThan:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name]: {
|
||||||
|
gte: parseFloat(filter.value),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
case ViewFilterOperand.LessThan:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name]: {
|
||||||
|
lte: parseFloat(filter.value),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'RELATION':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case ViewFilterOperand.Is:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name + 'Id']: {
|
||||||
|
eq: filter.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
case ViewFilterOperand.IsNot:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name + 'Id']: {
|
||||||
|
neq: filter.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'CURRENCY':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case ViewFilterOperand.GreaterThan:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name]: {
|
||||||
|
amountMicros: { gte: parseFloat(filter.value) * 1000000 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
case ViewFilterOperand.LessThan:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name]: {
|
||||||
|
amountMicros: { lte: parseFloat(filter.value) * 1000000 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'LINK':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case ViewFilterOperand.Contains:
|
||||||
|
whereClause.push({
|
||||||
|
[correspondingField.name]: {
|
||||||
|
url: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
case ViewFilterOperand.DoesNotContain:
|
||||||
|
whereClause.push({
|
||||||
|
not: {
|
||||||
|
[correspondingField.name]: {
|
||||||
|
url: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'FULL_NAME':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case ViewFilterOperand.Contains:
|
||||||
|
whereClause.push({
|
||||||
|
or: [
|
||||||
|
{
|
||||||
|
[correspondingField.name]: {
|
||||||
|
firstName: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[correspondingField.name]: {
|
||||||
|
firstName: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
case ViewFilterOperand.DoesNotContain:
|
||||||
|
whereClause.push({
|
||||||
|
and: [
|
||||||
|
{
|
||||||
|
not: {
|
||||||
|
[correspondingField.name]: {
|
||||||
|
firstName: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
not: {
|
||||||
|
[correspondingField.name]: {
|
||||||
|
lastName: {
|
||||||
|
ilike: `%${filter.value}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -100,5 +217,6 @@ export const turnFiltersIntoWhereClauseV2 = (
|
|||||||
throw new Error('Unknown filter type');
|
throw new Error('Unknown filter type');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return whereClause;
|
|
||||||
|
return { and: whereClause };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -166,7 +166,7 @@ export const useViewFilters = (viewScopeId: string) => {
|
|||||||
filter.fieldMetadataId === filterToUpsert.fieldMetadataId,
|
filter.fieldMetadataId === filterToUpsert.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (existingFilterIndex === -1) {
|
if (existingFilterIndex === -1 && filterToUpsert.value !== '') {
|
||||||
filtersDraft.push({
|
filtersDraft.push({
|
||||||
...filterToUpsert,
|
...filterToUpsert,
|
||||||
id: existingSavedFilterId,
|
id: existingSavedFilterId,
|
||||||
@ -174,6 +174,11 @@ export const useViewFilters = (viewScopeId: string) => {
|
|||||||
return filtersDraft;
|
return filtersDraft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filterToUpsert.value === '') {
|
||||||
|
filtersDraft.splice(existingFilterIndex, 1);
|
||||||
|
return filtersDraft;
|
||||||
|
}
|
||||||
|
|
||||||
filtersDraft[existingFilterIndex] = {
|
filtersDraft[existingFilterIndex] = {
|
||||||
...filterToUpsert,
|
...filterToUpsert,
|
||||||
id: existingSavedFilterId,
|
id: existingSavedFilterId,
|
||||||
|
|||||||
@ -19,14 +19,12 @@ export const opportunityBoardFilterDefinitions: FilterDefinitionByEntity<Opportu
|
|||||||
fieldMetadataId: 'companyId',
|
fieldMetadataId: 'companyId',
|
||||||
label: 'Company',
|
label: 'Company',
|
||||||
iconName: 'IconBuildingSkyscraper',
|
iconName: 'IconBuildingSkyscraper',
|
||||||
type: 'ENTITY',
|
type: 'RELATION',
|
||||||
// entitySelectComponent: <FilterDropdownCompanySearchSelect />,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldMetadataId: 'pointOfContactId',
|
fieldMetadataId: 'pointOfContactId',
|
||||||
label: 'Point of contact',
|
label: 'Point of contact',
|
||||||
iconName: 'IconUser',
|
iconName: 'IconUser',
|
||||||
type: 'ENTITY',
|
type: 'RELATION',
|
||||||
//entitySelectComponent: <FilterDropdownPeopleSearchSelect />,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export const tasksFilterDefinitions: FilterDefinitionByEntity<Activity>[] = [
|
|||||||
fieldMetadataId: 'assigneeId',
|
fieldMetadataId: 'assigneeId',
|
||||||
label: 'Assignee',
|
label: 'Assignee',
|
||||||
iconName: 'IconUser',
|
iconName: 'IconUser',
|
||||||
type: 'ENTITY',
|
type: 'RELATION',
|
||||||
entitySelectComponent: <FilterDropdownUserSearchSelect />,
|
entitySelectComponent: <FilterDropdownUserSearchSelect />,
|
||||||
selectAllLabel: 'All assignees',
|
selectAllLabel: 'All assignees',
|
||||||
SelectAllIcon: IconUserCircle,
|
SelectAllIcon: IconUserCircle,
|
||||||
|
|||||||
Reference in New Issue
Block a user