New branch based on feedback in PR #8950 and issue #8016 --------- Co-authored-by: ad-elias <elias@autodiligence.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -15,6 +15,7 @@ import { DELETE_MAX_COUNT } from '@/object-record/constants/DeleteMaxCount';
|
|||||||
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
|
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
|
||||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||||
import { FilterOperand } from '@/object-record/object-filter-dropdown/types/FilterOperand';
|
import { FilterOperand } from '@/object-record/object-filter-dropdown/types/FilterOperand';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||||
@ -52,10 +53,13 @@ export const useDeleteMultipleRecordsAction = ({
|
|||||||
contextStoreFiltersComponentState,
|
contextStoreFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const graphqlFilter = computeContextStoreFilters(
|
const graphqlFilter = computeContextStoreFilters(
|
||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
const deletedAtFieldMetadata = objectMetadataItem.fields.find(
|
const deletedAtFieldMetadata = objectMetadataItem.fields.find(
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s
|
|||||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
export const useFindManyRecordsSelectedInContextStore = ({
|
export const useFindManyRecordsSelectedInContextStore = ({
|
||||||
@ -30,10 +31,13 @@ export const useFindManyRecordsSelectedInContextStore = ({
|
|||||||
instanceId,
|
instanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const queryFilter = computeContextStoreFilters(
|
const queryFilter = computeContextStoreFilters(
|
||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { records, loading, totalCount } = useFindManyRecords({
|
const { records, loading, totalCount } = useFindManyRecords({
|
||||||
|
|||||||
@ -1,14 +1,20 @@
|
|||||||
import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||||
|
import { FilterValueDependencies } from '@/object-record/record-filter/types/FilterValueDependencies';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
import { expect } from '@storybook/test';
|
import { expect } from '@storybook/test';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
describe('computeContextStoreFilters', () => {
|
describe('computeContextStoreFilters', () => {
|
||||||
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
const mockFilterValueDependencies: FilterValueDependencies = {
|
||||||
|
currentWorkspaceMemberId: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
||||||
|
};
|
||||||
|
|
||||||
it('should work for selection mode', () => {
|
it('should work for selection mode', () => {
|
||||||
const contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule = {
|
const contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule = {
|
||||||
mode: 'selection',
|
mode: 'selection',
|
||||||
@ -19,6 +25,7 @@ describe('computeContextStoreFilters', () => {
|
|||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
[],
|
[],
|
||||||
personObjectMetadataItem,
|
personObjectMetadataItem,
|
||||||
|
mockFilterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(filters).toEqual({
|
expect(filters).toEqual({
|
||||||
@ -61,6 +68,7 @@ describe('computeContextStoreFilters', () => {
|
|||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
personObjectMetadataItem,
|
personObjectMetadataItem,
|
||||||
|
mockFilterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(filters).toEqual({
|
expect(filters).toEqual({
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextS
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||||
|
import { FilterValueDependencies } from '@/object-record/record-filter/types/FilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||||
|
|
||||||
@ -9,12 +10,14 @@ export const computeContextStoreFilters = (
|
|||||||
contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters: Filter[],
|
contextStoreFilters: Filter[],
|
||||||
objectMetadataItem: ObjectMetadataItem,
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
|
filterValueDependencies: FilterValueDependencies,
|
||||||
) => {
|
) => {
|
||||||
let queryFilter: RecordGqlOperationFilter | undefined;
|
let queryFilter: RecordGqlOperationFilter | undefined;
|
||||||
|
|
||||||
if (contextStoreTargetedRecordsRule.mode === 'exclusion') {
|
if (contextStoreTargetedRecordsRule.mode === 'exclusion') {
|
||||||
queryFilter = makeAndFilterVariables([
|
queryFilter = makeAndFilterVariables([
|
||||||
computeViewRecordGqlOperationFilter(
|
computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
[],
|
[],
|
||||||
@ -39,6 +42,7 @@ export const computeContextStoreFilters = (
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
: computeViewRecordGqlOperationFilter(
|
: computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
[],
|
[],
|
||||||
|
|||||||
@ -8,10 +8,10 @@ import { InternalDatePicker } from '@/ui/input/components/internal/date/componen
|
|||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
import { computeVariableDateViewFilterValue } from '@/views/view-filter-value/utils/computeVariableDateViewFilterValue';
|
import { computeVariableDateViewFilterValue } from '@/views/view-filter-value/utils/computeVariableDateViewFilterValue';
|
||||||
import {
|
import {
|
||||||
|
resolveDateViewFilterValue,
|
||||||
VariableDateViewFilterValueDirection,
|
VariableDateViewFilterValueDirection,
|
||||||
VariableDateViewFilterValueUnit,
|
VariableDateViewFilterValueUnit,
|
||||||
} from '@/views/view-filter-value/utils/resolveDateViewFilterValue';
|
} from '@/views/view-filter-value/utils/resolveDateViewFilterValue';
|
||||||
import { resolveFilterValue } from '@/views/view-filter-value/utils/resolveFilterValue';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
@ -37,7 +37,7 @@ export const ObjectFilterDropdownDateInput = () => {
|
|||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
const initialFilterValue = selectedFilter
|
const initialFilterValue = selectedFilter
|
||||||
? resolveFilterValue(selectedFilter)
|
? resolveDateViewFilterValue(selectedFilter)
|
||||||
: null;
|
: null;
|
||||||
const [internalDate, setInternalDate] = useState<Date | null>(
|
const [internalDate, setInternalDate] = useState<Date | null>(
|
||||||
initialFilterValue instanceof Date ? initialFilterValue : null,
|
initialFilterValue instanceof Date ? initialFilterValue : null,
|
||||||
@ -98,7 +98,7 @@ export const ObjectFilterDropdownDateInput = () => {
|
|||||||
selectedOperandInDropdown === ViewFilterOperand.IsRelative;
|
selectedOperandInDropdown === ViewFilterOperand.IsRelative;
|
||||||
|
|
||||||
const resolvedValue = selectedFilter
|
const resolvedValue = selectedFilter
|
||||||
? resolveFilterValue(selectedFilter)
|
? resolveDateViewFilterValue(selectedFilter)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const relativeDate =
|
const relativeDate =
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
||||||
|
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { MenuItemMultiSelectAvatar } from 'twenty-ui';
|
||||||
|
|
||||||
|
const StyledPinnedItemsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ObjectFilterDropdownRecordPinnedItems = (props: {
|
||||||
|
selectableItems: SelectableItem[];
|
||||||
|
onChange: (
|
||||||
|
selectableItem: SelectableItem,
|
||||||
|
isNewCheckedValue: boolean,
|
||||||
|
) => void;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<StyledPinnedItemsContainer>
|
||||||
|
{props.selectableItems.map((selectableItem) => {
|
||||||
|
return (
|
||||||
|
<MenuItemMultiSelectAvatar
|
||||||
|
key={selectableItem.id}
|
||||||
|
selected={selectableItem.isSelected}
|
||||||
|
onSelectChange={(newCheckedValue) => {
|
||||||
|
props.onChange(selectableItem, newCheckedValue);
|
||||||
|
}}
|
||||||
|
avatar={
|
||||||
|
<StyledMultipleSelectDropdownAvatarChip
|
||||||
|
className="avatar-icon-container"
|
||||||
|
name={selectableItem.name}
|
||||||
|
avatarUrl={selectableItem.avatarUrl}
|
||||||
|
LeftIcon={selectableItem.AvatarIcon}
|
||||||
|
avatarType={selectableItem.avatarType}
|
||||||
|
isIconInverted={selectableItem.isIconInverted}
|
||||||
|
placeholderColorSeed={selectableItem.id}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</StyledPinnedItemsContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -2,16 +2,26 @@ import { useState } from 'react';
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { ObjectFilterDropdownRecordPinnedItems } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordPinnedItems';
|
||||||
|
import { CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID } from '@/object-record/object-filter-dropdown/constants/CurrentWorkspaceMemberSelectableItemId';
|
||||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown';
|
import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown';
|
||||||
import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect';
|
import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect';
|
||||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||||
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
|
import { RelationFilterValue } from '@/views/view-filter-value/types/RelationFilterValue';
|
||||||
|
import { relationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/relationFilterValueSchema';
|
||||||
|
import { IconUserCircle } from 'twenty-ui';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const EMPTY_FILTER_VALUE = '[]';
|
export const EMPTY_FILTER_VALUE: string = JSON.stringify({
|
||||||
|
isCurrentWorkspaceMemberSelected: false,
|
||||||
|
selectedRecordIds: [],
|
||||||
|
} satisfies RelationFilterValue);
|
||||||
|
|
||||||
export const MAX_RECORDS_TO_DISPLAY = 3;
|
export const MAX_RECORDS_TO_DISPLAY = 3;
|
||||||
|
|
||||||
type ObjectFilterDropdownRecordSelectProps = {
|
type ObjectFilterDropdownRecordSelectProps = {
|
||||||
@ -26,15 +36,10 @@ export const ObjectFilterDropdownRecordSelect = ({
|
|||||||
objectFilterDropdownSearchInputState,
|
objectFilterDropdownSearchInputState,
|
||||||
selectedOperandInDropdownState,
|
selectedOperandInDropdownState,
|
||||||
selectedFilterState,
|
selectedFilterState,
|
||||||
setObjectFilterDropdownSelectedRecordIds,
|
|
||||||
objectFilterDropdownSelectedRecordIdsState,
|
objectFilterDropdownSelectedRecordIdsState,
|
||||||
selectFilter,
|
selectFilter,
|
||||||
emptyFilterButKeepDefinition,
|
|
||||||
} = useFilterDropdown();
|
} = useFilterDropdown();
|
||||||
|
|
||||||
const { deleteCombinedViewFilter } =
|
|
||||||
useDeleteCombinedViewFilters(viewComponentId);
|
|
||||||
|
|
||||||
const { currentViewWithCombinedFiltersAndSorts } =
|
const { currentViewWithCombinedFiltersAndSorts } =
|
||||||
useGetCurrentView(viewComponentId);
|
useGetCurrentView(viewComponentId);
|
||||||
|
|
||||||
@ -54,9 +59,26 @@ export const ObjectFilterDropdownRecordSelect = ({
|
|||||||
|
|
||||||
const selectedFilter = useRecoilValue(selectedFilterState);
|
const selectedFilter = useRecoilValue(selectedFilterState);
|
||||||
|
|
||||||
|
const { isCurrentWorkspaceMemberSelected } = relationFilterValueSchema
|
||||||
|
.catch({
|
||||||
|
isCurrentWorkspaceMemberSelected: false,
|
||||||
|
selectedRecordIds: [],
|
||||||
|
})
|
||||||
|
.parse(selectedFilter?.value);
|
||||||
|
|
||||||
const objectNameSingular =
|
const objectNameSingular =
|
||||||
filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular;
|
filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular;
|
||||||
|
|
||||||
|
if (!isDefined(objectNameSingular)) {
|
||||||
|
throw new Error('relationObjectMetadataNameSingular is not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
|
objectNameSingular: objectNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const objectLabelPlural = objectMetadataItem?.labelPlural;
|
||||||
|
|
||||||
if (!isDefined(objectNameSingular)) {
|
if (!isDefined(objectNameSingular)) {
|
||||||
throw new Error('objectNameSingular is not defined');
|
throw new Error('objectNameSingular is not defined');
|
||||||
}
|
}
|
||||||
@ -69,27 +91,53 @@ export const ObjectFilterDropdownRecordSelect = ({
|
|||||||
limit: 10,
|
limit: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const currentWorkspaceMemberSelectableItem: SelectableItem = {
|
||||||
|
id: CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID,
|
||||||
|
name: 'Me',
|
||||||
|
isSelected: isCurrentWorkspaceMemberSelected,
|
||||||
|
AvatarIcon: IconUserCircle,
|
||||||
|
};
|
||||||
|
|
||||||
|
const pinnedSelectableItems: SelectableItem[] =
|
||||||
|
objectNameSingular === 'workspaceMember'
|
||||||
|
? [currentWorkspaceMemberSelectableItem]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const filteredPinnedSelectableItems = pinnedSelectableItems.filter((item) =>
|
||||||
|
item.name
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(objectFilterDropdownSearchInput.toLowerCase()),
|
||||||
|
);
|
||||||
|
|
||||||
const handleMultipleRecordSelectChange = (
|
const handleMultipleRecordSelectChange = (
|
||||||
recordToSelect: SelectableItem,
|
itemToSelect: SelectableItem,
|
||||||
newSelectedValue: boolean,
|
isNewSelectedValue: boolean,
|
||||||
) => {
|
) => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newSelectedRecordIds = newSelectedValue
|
const isItemCurrentWorkspaceMember =
|
||||||
? [...objectFilterDropdownSelectedRecordIds, recordToSelect.id]
|
itemToSelect.id === CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID;
|
||||||
: objectFilterDropdownSelectedRecordIds.filter(
|
|
||||||
(id) => id !== recordToSelect.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (newSelectedRecordIds.length === 0) {
|
const selectedRecordIdsWithAddedRecord = [
|
||||||
emptyFilterButKeepDefinition();
|
...objectFilterDropdownSelectedRecordIds,
|
||||||
deleteCombinedViewFilter(fieldId);
|
itemToSelect.id,
|
||||||
return;
|
];
|
||||||
}
|
const selectedRecordIdsWithRemovedRecord =
|
||||||
|
objectFilterDropdownSelectedRecordIds.filter(
|
||||||
|
(id) => id !== itemToSelect.id,
|
||||||
|
);
|
||||||
|
|
||||||
setObjectFilterDropdownSelectedRecordIds(newSelectedRecordIds);
|
const newSelectedRecordIds = isItemCurrentWorkspaceMember
|
||||||
|
? objectFilterDropdownSelectedRecordIds
|
||||||
|
: isNewSelectedValue
|
||||||
|
? selectedRecordIdsWithAddedRecord
|
||||||
|
: selectedRecordIdsWithRemovedRecord;
|
||||||
|
|
||||||
|
const newIsCurrentWorkspaceMemberSelected = isItemCurrentWorkspaceMember
|
||||||
|
? isNewSelectedValue
|
||||||
|
: isCurrentWorkspaceMemberSelected;
|
||||||
|
|
||||||
const selectedRecordNames = [
|
const selectedRecordNames = [
|
||||||
...recordsToSelect,
|
...recordsToSelect,
|
||||||
@ -103,19 +151,32 @@ export const ObjectFilterDropdownRecordSelect = ({
|
|||||||
.filter((record) => newSelectedRecordIds.includes(record.id))
|
.filter((record) => newSelectedRecordIds.includes(record.id))
|
||||||
.map((record) => record.name);
|
.map((record) => record.name);
|
||||||
|
|
||||||
|
const selectedPinnedItemNames = newIsCurrentWorkspaceMemberSelected
|
||||||
|
? [currentWorkspaceMemberSelectableItem.name]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const selectedItemNames = [
|
||||||
|
...selectedPinnedItemNames,
|
||||||
|
...selectedRecordNames,
|
||||||
|
];
|
||||||
|
|
||||||
const filterDisplayValue =
|
const filterDisplayValue =
|
||||||
selectedRecordNames.length > MAX_RECORDS_TO_DISPLAY
|
selectedItemNames.length > MAX_RECORDS_TO_DISPLAY
|
||||||
? `${selectedRecordNames.length} companies`
|
? `${selectedItemNames.length} ${objectLabelPlural.toLowerCase()}`
|
||||||
: selectedRecordNames.join(', ');
|
: selectedItemNames.join(', ');
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isDefined(filterDefinitionUsedInDropdown) &&
|
isDefined(filterDefinitionUsedInDropdown) &&
|
||||||
isDefined(selectedOperandInDropdown)
|
isDefined(selectedOperandInDropdown)
|
||||||
) {
|
) {
|
||||||
const newFilterValue =
|
const newFilterValue =
|
||||||
newSelectedRecordIds.length > 0
|
newSelectedRecordIds.length > 0 || newIsCurrentWorkspaceMemberSelected
|
||||||
? JSON.stringify(newSelectedRecordIds)
|
? JSON.stringify({
|
||||||
: EMPTY_FILTER_VALUE;
|
isCurrentWorkspaceMemberSelected:
|
||||||
|
newIsCurrentWorkspaceMemberSelected,
|
||||||
|
selectedRecordIds: newSelectedRecordIds,
|
||||||
|
} satisfies RelationFilterValue)
|
||||||
|
: '';
|
||||||
|
|
||||||
const viewFilter =
|
const viewFilter =
|
||||||
currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
|
currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
|
||||||
@ -139,15 +200,26 @@ export const ObjectFilterDropdownRecordSelect = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultipleSelectDropdown
|
<>
|
||||||
selectableListId="object-filter-record-select-id"
|
{filteredPinnedSelectableItems.length > 0 && (
|
||||||
hotkeyScope={RelationPickerHotkeyScope.RelationPicker}
|
<>
|
||||||
itemsToSelect={recordsToSelect}
|
<ObjectFilterDropdownRecordPinnedItems
|
||||||
filteredSelectedItems={filteredSelectedRecords}
|
selectableItems={filteredPinnedSelectableItems}
|
||||||
selectedItems={selectedRecords}
|
onChange={handleMultipleRecordSelectChange}
|
||||||
onChange={handleMultipleRecordSelectChange}
|
/>
|
||||||
searchFilter={objectFilterDropdownSearchInput}
|
<DropdownMenuSeparator />
|
||||||
loadingItems={loading}
|
</>
|
||||||
/>
|
)}
|
||||||
|
<MultipleSelectDropdown
|
||||||
|
selectableListId="object-filter-record-select-id"
|
||||||
|
hotkeyScope={RelationPickerHotkeyScope.RelationPicker}
|
||||||
|
itemsToSelect={recordsToSelect}
|
||||||
|
filteredSelectedItems={filteredSelectedRecords}
|
||||||
|
selectedItems={selectedRecords}
|
||||||
|
onChange={handleMultipleRecordSelectChange}
|
||||||
|
searchFilter={objectFilterDropdownSearchInput}
|
||||||
|
loadingItems={loading}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
export const CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID =
|
||||||
|
'CURRENT_WORKSPACE_MEMBER';
|
||||||
@ -3,6 +3,7 @@ import { RecordBoardContext } from '@/object-record/record-board/contexts/Record
|
|||||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||||
import { buildRecordGqlFieldsAggregateForRecordBoard } from '@/object-record/record-board/record-board-column/utils/buildRecordGqlFieldsAggregateForRecordBoard';
|
import { buildRecordGqlFieldsAggregateForRecordBoard } from '@/object-record/record-board/record-board-column/utils/buildRecordGqlFieldsAggregateForRecordBoard';
|
||||||
import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel';
|
import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
||||||
@ -53,7 +54,11 @@ export const useAggregateRecordsForRecordBoardColumn = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
recordIndexFilters,
|
recordIndexFilters,
|
||||||
objectMetadataItem.fields,
|
objectMetadataItem.fields,
|
||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
|
import { FilterValueDependencies } from '@/object-record/record-filter/types/FilterValueDependencies';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useFilterValueDependencies = (): {
|
||||||
|
filterValueDependencies: FilterValueDependencies;
|
||||||
|
} => {
|
||||||
|
const { id: currentWorkspaceMemberId } =
|
||||||
|
useRecoilValue(currentWorkspaceMemberState) ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
filterValueDependencies: {
|
||||||
|
currentWorkspaceMemberId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
export interface FilterValueDependencies {
|
||||||
|
currentWorkspaceMemberId?: string;
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||||
|
import { FilterValueDependencies } from '@/object-record/record-filter/types/FilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
||||||
@ -14,6 +15,10 @@ const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
|||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
const mockFilterValueDependencies: FilterValueDependencies = {
|
||||||
|
currentWorkspaceMemberId: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
||||||
|
};
|
||||||
|
|
||||||
jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
|
jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
|
||||||
|
|
||||||
describe('computeViewRecordGqlOperationFilter', () => {
|
describe('computeViewRecordGqlOperationFilter', () => {
|
||||||
@ -38,6 +43,7 @@ describe('computeViewRecordGqlOperationFilter', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[nameFilter],
|
[nameFilter],
|
||||||
companyMockObjectMetadataItem.fields,
|
companyMockObjectMetadataItem.fields,
|
||||||
[],
|
[],
|
||||||
@ -90,6 +96,7 @@ describe('computeViewRecordGqlOperationFilter', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[nameFilter, employeesFilter],
|
[nameFilter, employeesFilter],
|
||||||
companyMockObjectMetadataItem.fields,
|
companyMockObjectMetadataItem.fields,
|
||||||
[],
|
[],
|
||||||
@ -176,6 +183,7 @@ describe('should work as expected for the different field types', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[
|
[
|
||||||
addressFilterContains,
|
addressFilterContains,
|
||||||
addressFilterDoesNotContain,
|
addressFilterDoesNotContain,
|
||||||
@ -558,6 +566,7 @@ describe('should work as expected for the different field types', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[
|
[
|
||||||
phonesFilterContains,
|
phonesFilterContains,
|
||||||
phonesFilterDoesNotContain,
|
phonesFilterDoesNotContain,
|
||||||
@ -759,6 +768,7 @@ describe('should work as expected for the different field types', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[
|
[
|
||||||
emailsFilterContains,
|
emailsFilterContains,
|
||||||
emailsFilterDoesNotContain,
|
emailsFilterDoesNotContain,
|
||||||
@ -914,6 +924,7 @@ describe('should work as expected for the different field types', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[
|
[
|
||||||
dateFilterIsAfter,
|
dateFilterIsAfter,
|
||||||
dateFilterIsBefore,
|
dateFilterIsBefore,
|
||||||
@ -1030,6 +1041,7 @@ describe('should work as expected for the different field types', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = computeViewRecordGqlOperationFilter(
|
const result = computeViewRecordGqlOperationFilter(
|
||||||
|
mockFilterValueDependencies,
|
||||||
[
|
[
|
||||||
employeesFilterIsGreaterThan,
|
employeesFilterIsGreaterThan,
|
||||||
employeesFilterIsLessThan,
|
employeesFilterIsLessThan,
|
||||||
|
|||||||
@ -28,14 +28,18 @@ import {
|
|||||||
convertRatingToRatingValue,
|
convertRatingToRatingValue,
|
||||||
} from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
|
} from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
|
||||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||||
|
import { FilterValueDependencies } from '@/object-record/record-filter/types/FilterValueDependencies';
|
||||||
import { getEmptyRecordGqlOperationFilter } from '@/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter';
|
import { getEmptyRecordGqlOperationFilter } from '@/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter';
|
||||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||||
import { resolveFilterValue } from '@/views/view-filter-value/utils/resolveFilterValue';
|
import { resolveDateViewFilterValue } from '@/views/view-filter-value/utils/resolveDateViewFilterValue';
|
||||||
|
import { resolveSelectViewFilterValue } from '@/views/view-filter-value/utils/resolveSelectViewFilterValue';
|
||||||
|
import { relationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/relationFilterValueSchema';
|
||||||
import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns';
|
import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const computeFilterRecordGqlOperationFilter = (
|
const computeFilterRecordGqlOperationFilter = (
|
||||||
|
filterValueDependencies: FilterValueDependencies,
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
fields: Pick<Field, 'id' | 'name'>[],
|
||||||
): RecordGqlOperationFilter | undefined => {
|
): RecordGqlOperationFilter | undefined => {
|
||||||
@ -124,7 +128,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
}
|
}
|
||||||
case 'DATE':
|
case 'DATE':
|
||||||
case 'DATE_TIME': {
|
case 'DATE_TIME': {
|
||||||
const resolvedFilterValue = resolveFilterValue(filter);
|
const resolvedFilterValue = resolveDateViewFilterValue(filter);
|
||||||
const now = roundToNearestMinutes(new Date());
|
const now = roundToNearestMinutes(new Date());
|
||||||
const date =
|
const date =
|
||||||
resolvedFilterValue instanceof Date ? resolvedFilterValue : now;
|
resolvedFilterValue instanceof Date ? resolvedFilterValue : now;
|
||||||
@ -157,11 +161,8 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
.object({ start: z.date(), end: z.date() })
|
.object({ start: z.date(), end: z.date() })
|
||||||
.safeParse(resolvedFilterValue).data;
|
.safeParse(resolvedFilterValue).data;
|
||||||
|
|
||||||
const defaultDateRange = resolveFilterValue({
|
const defaultDateRange = resolveDateViewFilterValue({
|
||||||
value: 'PAST_1_DAY',
|
value: 'PAST_1_DAY',
|
||||||
definition: {
|
|
||||||
type: 'DATE',
|
|
||||||
},
|
|
||||||
operand: ViewFilterOperand.IsRelative,
|
operand: ViewFilterOperand.IsRelative,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -303,32 +304,41 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
}
|
}
|
||||||
case 'RELATION': {
|
case 'RELATION': {
|
||||||
if (!isEmptyOperand) {
|
if (!isEmptyOperand) {
|
||||||
try {
|
const { isCurrentWorkspaceMemberSelected, selectedRecordIds } =
|
||||||
JSON.parse(filter.value);
|
relationFilterValueSchema.parse(filter.value);
|
||||||
} catch (e) {
|
|
||||||
throw new Error(
|
|
||||||
`Cannot parse filter value for RELATION filter : "${filter.value}"`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedRecordIds = JSON.parse(filter.value) as string[];
|
const recordIds = isCurrentWorkspaceMemberSelected
|
||||||
|
? [
|
||||||
|
...selectedRecordIds,
|
||||||
|
filterValueDependencies.currentWorkspaceMemberId,
|
||||||
|
]
|
||||||
|
: selectedRecordIds;
|
||||||
|
|
||||||
if (parsedRecordIds.length === 0) return;
|
if (recordIds.length === 0) return;
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case ViewFilterOperand.Is:
|
case ViewFilterOperand.Is:
|
||||||
return {
|
return {
|
||||||
[correspondingField.name + 'Id']: {
|
[correspondingField.name + 'Id']: {
|
||||||
in: parsedRecordIds,
|
in: recordIds,
|
||||||
} as RelationFilter,
|
} as RelationFilter,
|
||||||
};
|
};
|
||||||
case ViewFilterOperand.IsNot: {
|
case ViewFilterOperand.IsNot: {
|
||||||
if (parsedRecordIds.length === 0) return;
|
if (recordIds.length === 0) return;
|
||||||
return {
|
return {
|
||||||
not: {
|
or: [
|
||||||
[correspondingField.name + 'Id']: {
|
{
|
||||||
in: parsedRecordIds,
|
not: {
|
||||||
} as RelationFilter,
|
[correspondingField.name + 'Id']: {
|
||||||
},
|
in: recordIds,
|
||||||
|
} as RelationFilter,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[correspondingField.name + 'Id']: {
|
||||||
|
is: 'NULL',
|
||||||
|
} as RelationFilter,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -611,9 +621,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = resolveFilterValue(
|
const options = resolveSelectViewFilterValue(filter);
|
||||||
filter as Filter & { definition: { type: 'MULTI_SELECT' } },
|
|
||||||
);
|
|
||||||
|
|
||||||
if (options.length === 0) return;
|
if (options.length === 0) return;
|
||||||
|
|
||||||
@ -660,9 +668,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
filter.definition,
|
filter.definition,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const options = resolveFilterValue(
|
const options = resolveSelectViewFilterValue(filter);
|
||||||
filter as Filter & { definition: { type: 'SELECT' } },
|
|
||||||
);
|
|
||||||
|
|
||||||
if (options.length === 0) return;
|
if (options.length === 0) return;
|
||||||
|
|
||||||
@ -869,6 +875,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const computeViewFilterGroupRecordGqlOperationFilter = (
|
const computeViewFilterGroupRecordGqlOperationFilter = (
|
||||||
|
filterValueDependencies: FilterValueDependencies,
|
||||||
filters: Filter[],
|
filters: Filter[],
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
fields: Pick<Field, 'id' | 'name'>[],
|
||||||
viewFilterGroups: ViewFilterGroup[],
|
viewFilterGroups: ViewFilterGroup[],
|
||||||
@ -887,7 +894,13 @@ const computeViewFilterGroupRecordGqlOperationFilter = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const groupRecordGqlOperationFilters = groupFilters
|
const groupRecordGqlOperationFilters = groupFilters
|
||||||
.map((filter) => computeFilterRecordGqlOperationFilter(filter, fields))
|
.map((filter) =>
|
||||||
|
computeFilterRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
|
filter,
|
||||||
|
fields,
|
||||||
|
),
|
||||||
|
)
|
||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
|
|
||||||
const subGroupRecordGqlOperationFilters = viewFilterGroups
|
const subGroupRecordGqlOperationFilters = viewFilterGroups
|
||||||
@ -897,6 +910,7 @@ const computeViewFilterGroupRecordGqlOperationFilter = (
|
|||||||
)
|
)
|
||||||
.map((subViewFilterGroup) =>
|
.map((subViewFilterGroup) =>
|
||||||
computeViewFilterGroupRecordGqlOperationFilter(
|
computeViewFilterGroupRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
filters,
|
filters,
|
||||||
fields,
|
fields,
|
||||||
viewFilterGroups,
|
viewFilterGroups,
|
||||||
@ -932,6 +946,7 @@ const computeViewFilterGroupRecordGqlOperationFilter = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const computeViewRecordGqlOperationFilter = (
|
export const computeViewRecordGqlOperationFilter = (
|
||||||
|
filterValueDependencies: FilterValueDependencies,
|
||||||
filters: Filter[],
|
filters: Filter[],
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
fields: Pick<Field, 'id' | 'name'>[],
|
||||||
viewFilterGroups: ViewFilterGroup[],
|
viewFilterGroups: ViewFilterGroup[],
|
||||||
@ -939,7 +954,11 @@ export const computeViewRecordGqlOperationFilter = (
|
|||||||
const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = filters
|
const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = filters
|
||||||
.filter((filter) => !filter.viewFilterGroupId)
|
.filter((filter) => !filter.viewFilterGroupId)
|
||||||
.map((regularFilter) =>
|
.map((regularFilter) =>
|
||||||
computeFilterRecordGqlOperationFilter(regularFilter, fields),
|
computeFilterRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
|
regularFilter,
|
||||||
|
fields,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
|
|
||||||
@ -949,6 +968,7 @@ export const computeViewRecordGqlOperationFilter = (
|
|||||||
|
|
||||||
const advancedRecordGqlOperationFilter =
|
const advancedRecordGqlOperationFilter =
|
||||||
computeViewFilterGroupRecordGqlOperationFilter(
|
computeViewFilterGroupRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
filters,
|
filters,
|
||||||
fields,
|
fields,
|
||||||
viewFilterGroups,
|
viewFilterGroups,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { computeContextStoreFilters } from '@/context-store/utils/computeContext
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -40,6 +41,8 @@ export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
|||||||
contextStoreFiltersComponentState,
|
contextStoreFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const { totalCount } = useFindManyRecords({
|
const { totalCount } = useFindManyRecords({
|
||||||
...findManyRecordsParams,
|
...findManyRecordsParams,
|
||||||
recordGqlFields: {
|
recordGqlFields: {
|
||||||
@ -49,6 +52,7 @@ export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect =
|
|||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
),
|
),
|
||||||
limit: 1,
|
limit: 1,
|
||||||
skip: contextStoreTargetedRecordsRule.mode === 'selection',
|
skip: contextStoreTargetedRecordsRule.mode === 'selection',
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { computeContextStoreFilters } from '@/context-store/utils/computeContext
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/object-options-dropdown/constants/ExportTableDataDefaultPageSize';
|
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/object-options-dropdown/constants/ExportTableDataDefaultPageSize';
|
||||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
@ -71,10 +72,13 @@ export const useExportFetchRecords = ({
|
|||||||
contextStoreFiltersComponentState,
|
contextStoreFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const queryFilter = computeContextStoreFilters(
|
const queryFilter = computeContextStoreFilters(
|
||||||
contextStoreTargetedRecordsRule,
|
contextStoreTargetedRecordsRule,
|
||||||
contextStoreFilters,
|
contextStoreFilters,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
const findManyRecordsParams = useFindManyRecordIndexTableParams(
|
const findManyRecordsParams = useFindManyRecordIndexTableParams(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
|
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
|
||||||
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
||||||
@ -35,7 +36,10 @@ export const useFindManyRecordIndexTableParams = (
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const stateFilter = computeViewRecordGqlOperationFilter(
|
const stateFilter = computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
tableFilters,
|
tableFilters,
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
tableViewFilterGroups,
|
tableViewFilterGroups,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils
|
|||||||
import { useSetRecordBoardRecordIds } from '@/object-record/record-board/hooks/useSetRecordBoardRecordIds';
|
import { useSetRecordBoardRecordIds } from '@/object-record/record-board/hooks/useSetRecordBoardRecordIds';
|
||||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||||
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
||||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||||
@ -56,7 +57,11 @@ export const useLoadRecordIndexBoard = ({
|
|||||||
|
|
||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
recordIndexFilters,
|
recordIndexFilters,
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/useSetRecordIdsForColumn';
|
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/useSetRecordIdsForColumn';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
||||||
@ -43,7 +44,10 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
recordIndexFilters,
|
recordIndexFilters,
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
|
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
|
||||||
import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel';
|
import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
@ -26,7 +27,11 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
recordIndexFilters,
|
recordIndexFilters,
|
||||||
objectMetadataItem.fields,
|
objectMetadataItem.fields,
|
||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import styled from '@emotion/styled';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { AvatarChip, MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui';
|
import { MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
||||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||||
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -13,16 +13,6 @@ import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/inter
|
|||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
|
|
||||||
const StyledAvatarChip = styled(AvatarChip)`
|
|
||||||
&.avatar-icon-container {
|
|
||||||
color: ${({ theme }) => theme.font.color.secondary};
|
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const MultipleSelectDropdown = ({
|
export const MultipleSelectDropdown = ({
|
||||||
selectableListId,
|
selectableListId,
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
@ -129,7 +119,7 @@ export const MultipleSelectDropdown = ({
|
|||||||
handleItemSelectChange(item, newCheckedValue);
|
handleItemSelectChange(item, newCheckedValue);
|
||||||
}}
|
}}
|
||||||
avatar={
|
avatar={
|
||||||
<StyledAvatarChip
|
<StyledMultipleSelectDropdownAvatarChip
|
||||||
className="avatar-icon-container"
|
className="avatar-icon-container"
|
||||||
name={item.name}
|
name={item.name}
|
||||||
avatarUrl={item.avatarUrl}
|
avatarUrl={item.avatarUrl}
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { AvatarChip } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const StyledMultipleSelectDropdownAvatarChip = styled(AvatarChip)`
|
||||||
|
&.avatar-icon-container {
|
||||||
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -10,6 +10,7 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
|
|||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||||
|
import { relationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/relationFilterValueSchema';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
type ViewBarFilterEffectProps = {
|
type ViewBarFilterEffectProps = {
|
||||||
@ -69,12 +70,14 @@ export const ViewBarFilterEffect = ({
|
|||||||
filterDefinitionUsedInDropdown?.fieldMetadataId,
|
filterDefinitionUsedInDropdown?.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewFilterSelectedRecords = isNonEmptyString(
|
const { selectedRecordIds } = relationFilterValueSchema
|
||||||
viewFilterUsedInDropdown?.value,
|
.catch({
|
||||||
)
|
isCurrentWorkspaceMemberSelected: false,
|
||||||
? JSON.parse(viewFilterUsedInDropdown.value)
|
selectedRecordIds: [],
|
||||||
: [];
|
})
|
||||||
setObjectFilterDropdownSelectedRecordIds(viewFilterSelectedRecords);
|
.parse(viewFilterUsedInDropdown?.value);
|
||||||
|
|
||||||
|
setObjectFilterDropdownSelectedRecordIds(selectedRecordIds);
|
||||||
} else if (
|
} else if (
|
||||||
isDefined(filterDefinitionUsedInDropdown) &&
|
isDefined(filterDefinitionUsedInDropdown) &&
|
||||||
['SELECT', 'MULTI_SELECT'].includes(filterDefinitionUsedInDropdown.type)
|
['SELECT', 'MULTI_SELECT'].includes(filterDefinitionUsedInDropdown.type)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useActiveFieldMetadataItems } from '@/object-metadata/hooks/useActiveFieldMetadataItems';
|
import { useActiveFieldMetadataItems } from '@/object-metadata/hooks/useActiveFieldMetadataItems';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews';
|
import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews';
|
||||||
import { getQueryVariablesFromView } from '@/views/utils/getQueryVariablesFromView';
|
import { getQueryVariablesFromView } from '@/views/utils/getQueryVariablesFromView';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
@ -22,11 +23,14 @@ export const useQueryVariablesFromActiveFieldsOfViewOrDefaultView = ({
|
|||||||
|
|
||||||
const isJsonFilterEnabled = useIsFeatureEnabled('IS_JSON_FILTER_ENABLED');
|
const isJsonFilterEnabled = useIsFeatureEnabled('IS_JSON_FILTER_ENABLED');
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
const { filter, orderBy } = getQueryVariablesFromView({
|
const { filter, orderBy } = getQueryVariablesFromView({
|
||||||
fieldMetadataItems: activeFieldMetadataItems,
|
fieldMetadataItems: activeFieldMetadataItems,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
view,
|
view,
|
||||||
isJsonFilterEnabled,
|
isJsonFilterEnabled,
|
||||||
|
filterValueDependencies,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|||||||
import { formatFieldMetadataItemsAsFilterDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import { formatFieldMetadataItemsAsFilterDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions';
|
import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
|
import { FilterValueDependencies } from '@/object-record/record-filter/types/FilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
@ -14,11 +15,13 @@ export const getQueryVariablesFromView = ({
|
|||||||
fieldMetadataItems,
|
fieldMetadataItems,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
isJsonFilterEnabled,
|
isJsonFilterEnabled,
|
||||||
|
filterValueDependencies,
|
||||||
}: {
|
}: {
|
||||||
view: View | null | undefined;
|
view: View | null | undefined;
|
||||||
fieldMetadataItems: FieldMetadataItem[];
|
fieldMetadataItems: FieldMetadataItem[];
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
isJsonFilterEnabled: boolean;
|
isJsonFilterEnabled: boolean;
|
||||||
|
filterValueDependencies: FilterValueDependencies;
|
||||||
}) => {
|
}) => {
|
||||||
if (!isDefined(view)) {
|
if (!isDefined(view)) {
|
||||||
return {
|
return {
|
||||||
@ -39,6 +42,7 @@ export const getQueryVariablesFromView = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const filter = computeViewRecordGqlOperationFilter(
|
const filter = computeViewRecordGqlOperationFilter(
|
||||||
|
filterValueDependencies,
|
||||||
mapViewFiltersToFilters(viewFilters, filterDefinitions),
|
mapViewFiltersToFilters(viewFilters, filterDefinitions),
|
||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
viewFilterGroups ?? [],
|
viewFilterGroups ?? [],
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
import { relationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/relationFilterValueSchema';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export type RelationFilterValue = z.infer<typeof relationFilterValueSchema>;
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
|
||||||
|
|
||||||
export const resolveBooleanViewFilterValue = (
|
|
||||||
viewFilter: Pick<ViewFilter, 'value'>,
|
|
||||||
) => {
|
|
||||||
return viewFilter.value === 'true';
|
|
||||||
};
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
|
||||||
import { FilterableFieldType } from '@/object-record/object-filter-dropdown/types/FilterableFieldType';
|
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
|
||||||
import { resolveNumberViewFilterValue } from '@/views/view-filter-value/utils/resolveNumberViewFilterValue';
|
|
||||||
import { resolveSelectViewFilterValue } from '@/views/view-filter-value/utils/resolveSelectViewFilterValue';
|
|
||||||
import {
|
|
||||||
resolveDateViewFilterValue,
|
|
||||||
ResolvedDateViewFilterValue,
|
|
||||||
} from './resolveDateViewFilterValue';
|
|
||||||
import { resolveBooleanViewFilterValue } from '@/views/view-filter-value/utils/resolveBooleanViewFilterValue';
|
|
||||||
|
|
||||||
type ResolvedFilterValue<
|
|
||||||
T extends FilterableFieldType,
|
|
||||||
O extends ViewFilterOperand,
|
|
||||||
> = T extends 'DATE' | 'DATE_TIME'
|
|
||||||
? ResolvedDateViewFilterValue<O>
|
|
||||||
: T extends 'NUMBER'
|
|
||||||
? ReturnType<typeof resolveNumberViewFilterValue>
|
|
||||||
: T extends 'SELECT' | 'MULTI_SELECT'
|
|
||||||
? string[]
|
|
||||||
: T extends 'BOOLEAN'
|
|
||||||
? boolean
|
|
||||||
: string;
|
|
||||||
|
|
||||||
type PartialFilter<
|
|
||||||
T extends FilterableFieldType,
|
|
||||||
O extends ViewFilterOperand,
|
|
||||||
> = Pick<Filter, 'value'> & {
|
|
||||||
definition: { type: T };
|
|
||||||
operand: O;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resolveFilterValue = <
|
|
||||||
T extends FilterableFieldType,
|
|
||||||
O extends ViewFilterOperand,
|
|
||||||
>(
|
|
||||||
filter: PartialFilter<T, O>,
|
|
||||||
) => {
|
|
||||||
switch (filter.definition.type) {
|
|
||||||
case 'DATE':
|
|
||||||
case 'DATE_TIME':
|
|
||||||
return resolveDateViewFilterValue(filter) as ResolvedFilterValue<T, O>;
|
|
||||||
case 'NUMBER':
|
|
||||||
return resolveNumberViewFilterValue(filter) as ResolvedFilterValue<T, O>;
|
|
||||||
case 'SELECT':
|
|
||||||
case 'MULTI_SELECT':
|
|
||||||
return resolveSelectViewFilterValue(filter) as ResolvedFilterValue<T, O>;
|
|
||||||
case 'BOOLEAN':
|
|
||||||
return resolveBooleanViewFilterValue(filter) as ResolvedFilterValue<T, O>;
|
|
||||||
default:
|
|
||||||
return filter.value as ResolvedFilterValue<T, O>;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
|
||||||
|
|
||||||
export const resolveNumberViewFilterValue = (
|
|
||||||
viewFilter: Pick<ViewFilter, 'value'>,
|
|
||||||
) => {
|
|
||||||
return viewFilter.value === '' ? null : +viewFilter.value;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const relationFilterValueSchema = z
|
||||||
|
.string()
|
||||||
|
.transform((value, ctx) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch (error) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: (error as Error).message,
|
||||||
|
});
|
||||||
|
return z.NEVER;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
z.object({
|
||||||
|
isCurrentWorkspaceMemberSelected: z.boolean(),
|
||||||
|
selectedRecordIds: z.array(z.string()),
|
||||||
|
}),
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user