diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButton.tsx index bdb8fac66..c8d994105 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButton.tsx @@ -1,11 +1,9 @@ +import { AdvancedFilterFieldSelectDropdownButtonClickableSelect } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButtonClickableSelect'; import { AdvancedFilterFieldSelectDropdownContent } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownContent'; import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset'; import { useAdvancedFilterFieldSelectDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterFieldSelectDropdown'; -import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; const StyledContainer = styled.div` @@ -22,26 +20,13 @@ export const AdvancedFilterFieldSelectDropdownButton = ({ const { advancedFilterFieldSelectDropdownId } = useAdvancedFilterFieldSelectDropdown(recordFilterId); - const currentRecordFilters = useRecoilComponentValueV2( - currentRecordFiltersComponentState, - ); - - const recordFilter = currentRecordFilters.find( - (recordFilter) => recordFilter.id === recordFilterId, - ); - - const selectedFieldLabel = recordFilter?.label ?? ''; - return ( } dropdownComponents={ diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButtonClickableSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButtonClickableSelect.tsx new file mode 100644 index 000000000..368d85a76 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButtonClickableSelect.tsx @@ -0,0 +1,47 @@ +import { useGetFieldMetadataItemById } from '@/object-metadata/hooks/useGetFieldMetadataItemById'; +import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { SelectControl } from '@/ui/input/components/SelectControl'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isNonEmptyString } from '@sniptt/guards'; +import { isDefined } from 'twenty-shared/utils'; +import { useIcons } from 'twenty-ui'; + +type AdvancedFilterFieldSelectDropdownButtonClickableSelectProps = { + recordFilterId: string; +}; + +export const AdvancedFilterFieldSelectDropdownButtonClickableSelect = ({ + recordFilterId, +}: AdvancedFilterFieldSelectDropdownButtonClickableSelectProps) => { + const currentRecordFilters = useRecoilComponentValueV2( + currentRecordFiltersComponentState, + ); + + const recordFilter = currentRecordFilters.find( + (recordFilter) => recordFilter.id === recordFilterId, + ); + + const { getFieldMetadataItemById } = useGetFieldMetadataItemById(); + + const fieldMetadataItem = isNonEmptyString(recordFilter?.fieldMetadataId) + ? getFieldMetadataItemById(recordFilter?.fieldMetadataId) + : undefined; + + const { getIcon } = useIcons(); + + const fieldIcon = isDefined(fieldMetadataItem?.icon) + ? getIcon(fieldMetadataItem?.icon) + : undefined; + + const selectedFieldLabel = recordFilter?.label ?? ''; + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx index bdce7d9e3..190bf207a 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx @@ -1,3 +1,4 @@ +import { AdvancedFilterValueInputDropdownButtonClickableSelect } from '@/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect'; import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset'; import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; @@ -5,7 +6,6 @@ import { selectedFilterComponentState } from '@/object-record/object-filter-drop import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { configurableViewFilterOperands } from '@/object-record/object-filter-dropdown/utils/configurableViewFilterOperands'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; @@ -55,22 +55,15 @@ export const AdvancedFilterValueInputDropdownButton = ({ {operandHasNoInput ? ( <> ) : isDisabled ? ( - ) : ( } onOpen={() => { diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx new file mode 100644 index 000000000..62648bb2f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx @@ -0,0 +1,55 @@ +import { useGetFieldMetadataItemById } from '@/object-metadata/hooks/useGetFieldMetadataItemById'; +import { getAdvancedFilterInputPlaceholderText } from '@/object-record/advanced-filter/utils/getAdvancedFilterInputPlacedholderText'; +import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { SelectControl } from '@/ui/input/components/SelectControl'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isNonEmptyString } from '@sniptt/guards'; + +import { isDefined } from 'twenty-shared/utils'; + +type AdvancedFilterValueInputDropdownButtonClickableSelectProps = { + recordFilterId: string; +}; + +export const AdvancedFilterValueInputDropdownButtonClickableSelect = ({ + recordFilterId, +}: AdvancedFilterValueInputDropdownButtonClickableSelectProps) => { + const currentRecordFilters = useRecoilComponentValueV2( + currentRecordFiltersComponentState, + ); + + const recordFilter = currentRecordFilters.find( + (recordFilter) => recordFilter.id === recordFilterId, + ); + + const isDisabled = + !isDefined(recordFilter?.fieldMetadataId) || + !isDefined(recordFilter.operand); + + const shouldUsePlaceholder = !isNonEmptyString(recordFilter?.value); + + const { getFieldMetadataItemById } = useGetFieldMetadataItemById(); + + const fieldMetadataItem = isNonEmptyString(recordFilter?.fieldMetadataId) + ? getFieldMetadataItemById(recordFilter?.fieldMetadataId) + : undefined; + + const placeholderText = isDefined(fieldMetadataItem) + ? getAdvancedFilterInputPlaceholderText(fieldMetadataItem) + : 'Enter filter'; + + const advancedFilterInputText = shouldUsePlaceholder + ? placeholderText + : (recordFilter?.displayValue ?? ''); + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/utils/getAdvancedFilterInputPlacedholderText.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/utils/getAdvancedFilterInputPlacedholderText.ts new file mode 100644 index 000000000..64c048bc8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/utils/getAdvancedFilterInputPlacedholderText.ts @@ -0,0 +1,35 @@ +import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; + +// TODO: Refactor with composite filters +export const getAdvancedFilterInputPlaceholderText = ( + fieldMetadataItem: FieldMetadataItem, +) => { + switch (fieldMetadataItem.type) { + case FieldMetadataType.TEXT: + case FieldMetadataType.ADDRESS: + case FieldMetadataType.LINKS: + case FieldMetadataType.EMAILS: + case FieldMetadataType.NUMERIC: + case FieldMetadataType.RATING: + case FieldMetadataType.PHONES: + case FieldMetadataType.ARRAY: + case FieldMetadataType.FULL_NAME: + return `Enter value for ${fieldMetadataItem.label}`; + case FieldMetadataType.NUMBER: + return 'Enter number'; + case FieldMetadataType.DATE: + case FieldMetadataType.DATE_TIME: + return 'Enter date'; + case FieldMetadataType.ACTOR: + return 'Select actor'; + case FieldMetadataType.RELATION: + return `Select ${fieldMetadataItem.relationDefinition?.targetObjectMetadata.nameSingular}`; + case FieldMetadataType.SELECT: + case FieldMetadataType.MULTI_SELECT: + return `Select ${fieldMetadataItem.label}`; + + default: + return 'Enter value'; + } +}; diff --git a/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx b/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx index b1b5464b1..20c95d424 100644 --- a/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx @@ -8,10 +8,13 @@ import { SelectOption, } from 'twenty-ui'; +export type SelectControlTextAccent = 'default' | 'placeholder'; + const StyledControlContainer = styled.div<{ disabled?: boolean; hasIcon: boolean; selectSizeVariant?: SelectSizeVariant; + textAccent: SelectControlTextAccent; }>` display: grid; grid-template-columns: ${({ hasIcon }) => @@ -26,8 +29,12 @@ const StyledControlContainer = styled.div<{ background-color: ${({ theme }) => theme.background.transparent.lighter}; border: 1px solid ${({ theme }) => theme.border.color.medium}; border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ disabled, theme }) => - disabled ? theme.font.color.tertiary : theme.font.color.primary}; + color: ${({ disabled, theme, textAccent }) => + disabled + ? theme.font.color.tertiary + : textAccent === 'default' + ? theme.font.color.primary + : theme.font.color.secondary}; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; text-align: left; `; @@ -43,12 +50,14 @@ type SelectControlProps = { selectedOption: SelectOption; isDisabled?: boolean; selectSizeVariant?: SelectSizeVariant; + textAccent?: SelectControlTextAccent; }; export const SelectControl = ({ selectedOption, isDisabled, selectSizeVariant, + textAccent = 'default', }: SelectControlProps) => { const theme = useTheme(); @@ -57,6 +66,7 @@ export const SelectControl = ({ disabled={isDisabled} hasIcon={isDefined(selectedOption.Icon)} selectSizeVariant={selectSizeVariant} + textAccent={textAccent} > {isDefined(selectedOption.Icon) ? (