Implemented CRUD for view filter group and removed old states (#10590)
This PR implements CRUD for view filter groups with the new logic as already done for view filters and view sorts. It also completely removes the old combined view filter group states and usage. This PR is quite big but the impact is limited since it only changes advanced filters module, which is under feature flag at the moment, and it is already in a broken state so unusable, even if someone activates the feature flag.
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
@ -12,8 +11,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
@ -21,31 +19,29 @@ import { IconLibraryPlus, IconPlus, LightButton, MenuItem } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
type AdvancedFilterAddFilterRuleSelectProps = {
|
||||
viewFilterGroup: ViewFilterGroup;
|
||||
recordFilterGroup: RecordFilterGroup;
|
||||
lastChildPosition?: number;
|
||||
};
|
||||
|
||||
export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
viewFilterGroup,
|
||||
recordFilterGroup,
|
||||
lastChildPosition = 0,
|
||||
}: AdvancedFilterAddFilterRuleSelectProps) => {
|
||||
const dropdownId = `advanced-filter-add-filter-rule-${viewFilterGroup.id}`;
|
||||
const dropdownId = `advanced-filter-add-filter-rule-${recordFilterGroup.id}`;
|
||||
|
||||
const { currentViewId } = useGetCurrentView();
|
||||
|
||||
const { upsertCombinedViewFilterGroup } = useUpsertCombinedViewFilterGroup();
|
||||
const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup();
|
||||
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
|
||||
const newPositionInViewFilterGroup = lastChildPosition + 1;
|
||||
const newPositionInRecordFilterGroup = lastChildPosition + 1;
|
||||
|
||||
const { closeDropdown } = useDropdown(dropdownId);
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const objectMetadataId =
|
||||
currentViewWithCombinedFiltersAndSorts?.objectMetadataId;
|
||||
const objectMetadataId = currentView?.objectMetadataId;
|
||||
|
||||
if (!isDefined(objectMetadataId)) {
|
||||
throw new Error('Object metadata id is missing from current view');
|
||||
@ -100,8 +96,8 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
})[0],
|
||||
value: '',
|
||||
displayValue: '',
|
||||
viewFilterGroupId: viewFilterGroup.id,
|
||||
positionInViewFilterGroup: newPositionInViewFilterGroup,
|
||||
recordFilterGroupId: recordFilterGroup.id,
|
||||
positionInRecordFilterGroup: newPositionInRecordFilterGroup,
|
||||
label: defaultFieldMetadataItem.label,
|
||||
});
|
||||
};
|
||||
@ -115,23 +111,13 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
|
||||
const newRecordFilterGroupId = v4();
|
||||
|
||||
const newViewFilterGroup: ViewFilterGroup = {
|
||||
__typename: 'ViewFilterGroup',
|
||||
id: newRecordFilterGroupId,
|
||||
viewId: currentViewId,
|
||||
logicalOperator: ViewFilterGroupLogicalOperator.AND,
|
||||
parentViewFilterGroupId: viewFilterGroup.id,
|
||||
positionInViewFilterGroup: newPositionInViewFilterGroup,
|
||||
};
|
||||
|
||||
const newRecordFilterGroup: RecordFilterGroup = {
|
||||
id: newRecordFilterGroupId,
|
||||
logicalOperator: RecordFilterGroupLogicalOperator.AND,
|
||||
parentRecordFilterGroupId: viewFilterGroup.id,
|
||||
positionInRecordFilterGroup: newPositionInViewFilterGroup,
|
||||
parentRecordFilterGroupId: recordFilterGroup.id,
|
||||
positionInRecordFilterGroup: newPositionInRecordFilterGroup,
|
||||
};
|
||||
|
||||
upsertCombinedViewFilterGroup(newViewFilterGroup);
|
||||
upsertRecordFilterGroup(newRecordFilterGroup);
|
||||
|
||||
const defaultFieldMetadataItem = getDefaultFieldMetadataItem();
|
||||
@ -149,14 +135,14 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
||||
})[0],
|
||||
value: '',
|
||||
displayValue: '',
|
||||
viewFilterGroupId: newViewFilterGroup.id,
|
||||
positionInViewFilterGroup: newPositionInViewFilterGroup,
|
||||
recordFilterGroupId: newRecordFilterGroupId,
|
||||
positionInRecordFilterGroup: newPositionInRecordFilterGroup,
|
||||
label: defaultFieldMetadataItem.label,
|
||||
});
|
||||
};
|
||||
|
||||
const isFilterRuleGroupOptionVisible = !isDefined(
|
||||
viewFilterGroup.parentViewFilterGroupId,
|
||||
recordFilterGroup.parentRecordFilterGroupId,
|
||||
);
|
||||
|
||||
if (!isFilterRuleGroupOptionVisible) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { AdvancedFilterLogicalOperatorDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorDropdown';
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
|
||||
import styled from '@emotion/styled';
|
||||
import { capitalize } from 'twenty-shared';
|
||||
|
||||
@ -18,23 +19,23 @@ const StyledContainer = styled.div`
|
||||
|
||||
type AdvancedFilterLogicalOperatorCellProps = {
|
||||
index: number;
|
||||
viewFilterGroup: ViewFilterGroup;
|
||||
recordFilterGroup: RecordFilterGroup;
|
||||
};
|
||||
|
||||
export const AdvancedFilterLogicalOperatorCell = ({
|
||||
index,
|
||||
viewFilterGroup,
|
||||
recordFilterGroup,
|
||||
}: AdvancedFilterLogicalOperatorCellProps) => (
|
||||
<StyledContainer>
|
||||
{index === 0 ? (
|
||||
<StyledText>Where</StyledText>
|
||||
) : index === 1 ? (
|
||||
<AdvancedFilterLogicalOperatorDropdown
|
||||
viewFilterGroup={viewFilterGroup}
|
||||
recordFilterGroup={recordFilterGroup}
|
||||
/>
|
||||
) : (
|
||||
<StyledText>
|
||||
{capitalize(viewFilterGroup.logicalOperator.toLowerCase())}
|
||||
{capitalize(recordFilterGroup.logicalOperator.toLowerCase())}
|
||||
</StyledText>
|
||||
)}
|
||||
</StyledContainer>
|
||||
|
||||
@ -1,43 +1,33 @@
|
||||
import { ADVANCED_FILTER_LOGICAL_OPERATOR_OPTIONS } from '@/object-record/advanced-filter/constants/AdvancedFilterLogicalOperatorOptions';
|
||||
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||
|
||||
type AdvancedFilterLogicalOperatorDropdownProps = {
|
||||
viewFilterGroup: ViewFilterGroup;
|
||||
recordFilterGroup: RecordFilterGroup;
|
||||
};
|
||||
|
||||
export const AdvancedFilterLogicalOperatorDropdown = ({
|
||||
viewFilterGroup,
|
||||
recordFilterGroup,
|
||||
}: AdvancedFilterLogicalOperatorDropdownProps) => {
|
||||
const { upsertCombinedViewFilterGroup } = useUpsertCombinedViewFilterGroup();
|
||||
const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup();
|
||||
|
||||
const handleChange = (value: ViewFilterGroupLogicalOperator) => {
|
||||
upsertCombinedViewFilterGroup({
|
||||
...viewFilterGroup,
|
||||
logicalOperator: value,
|
||||
});
|
||||
|
||||
const handleChange = (value: RecordFilterGroupLogicalOperator) => {
|
||||
upsertRecordFilterGroup({
|
||||
id: viewFilterGroup.id,
|
||||
parentRecordFilterGroupId: viewFilterGroup.parentViewFilterGroupId,
|
||||
positionInRecordFilterGroup: viewFilterGroup.positionInViewFilterGroup,
|
||||
logicalOperator:
|
||||
value === ViewFilterGroupLogicalOperator.AND
|
||||
? RecordFilterGroupLogicalOperator.AND
|
||||
: RecordFilterGroupLogicalOperator.OR,
|
||||
id: recordFilterGroup.id,
|
||||
parentRecordFilterGroupId: recordFilterGroup.parentRecordFilterGroupId,
|
||||
positionInRecordFilterGroup:
|
||||
recordFilterGroup.positionInRecordFilterGroup,
|
||||
logicalOperator: value,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
fullWidth
|
||||
dropdownId={`advanced-filter-logical-operator-${viewFilterGroup.id}`}
|
||||
value={viewFilterGroup.logicalOperator}
|
||||
dropdownId={`advanced-filter-logical-operator-${recordFilterGroup.id}`}
|
||||
value={recordFilterGroup.logicalOperator}
|
||||
onChange={handleChange}
|
||||
options={ADVANCED_FILTER_LOGICAL_OPERATOR_OPTIONS}
|
||||
/>
|
||||
|
||||
@ -39,7 +39,7 @@ export const AdvancedFilterRootLevelViewFilterGroup = ({
|
||||
childViewFiltersAndViewFilterGroups,
|
||||
lastChildPosition,
|
||||
} = useCurrentViewViewFilterGroup({
|
||||
viewFilterGroupId: rootLevelViewFilterGroupId,
|
||||
recordFilterGroupId: rootLevelViewFilterGroupId,
|
||||
});
|
||||
|
||||
if (!isDefined(rootLevelViewFilterGroup)) {
|
||||
@ -53,7 +53,7 @@ export const AdvancedFilterRootLevelViewFilterGroup = ({
|
||||
<StyledRow key={child.id}>
|
||||
<AdvancedFilterLogicalOperatorCell
|
||||
index={i}
|
||||
viewFilterGroup={rootLevelViewFilterGroup}
|
||||
recordFilterGroup={rootLevelViewFilterGroup}
|
||||
/>
|
||||
<AdvancedFilterViewFilterGroup viewFilterGroupId={child.id} />
|
||||
<AdvancedFilterRuleOptionsDropdown viewFilterGroupId={child.id} />
|
||||
@ -62,7 +62,7 @@ export const AdvancedFilterRootLevelViewFilterGroup = ({
|
||||
<StyledRow key={child.id}>
|
||||
<AdvancedFilterLogicalOperatorCell
|
||||
index={i}
|
||||
viewFilterGroup={rootLevelViewFilterGroup}
|
||||
recordFilterGroup={rootLevelViewFilterGroup}
|
||||
/>
|
||||
<AdvancedFilterViewFilter viewFilterId={child.id} />
|
||||
<AdvancedFilterRuleOptionsDropdown viewFilterId={child.id} />
|
||||
@ -70,7 +70,7 @@ export const AdvancedFilterRootLevelViewFilterGroup = ({
|
||||
),
|
||||
)}
|
||||
<AdvancedFilterAddFilterRuleSelect
|
||||
viewFilterGroup={rootLevelViewFilterGroup}
|
||||
recordFilterGroup={rootLevelViewFilterGroup}
|
||||
lastChildPosition={lastChildPosition}
|
||||
/>
|
||||
</StyledContainer>
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { AdvancedFilterRuleOptionsDropdownButton } from '@/object-record/advanced-filter/components/AdvancedFilterRuleOptionsDropdownButton';
|
||||
|
||||
import { useCurrentViewViewFilterGroup } from '@/object-record/advanced-filter/hooks/useCurrentViewViewFilterGroup';
|
||||
import { useDeleteCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useDeleteCombinedViewFilterGroup';
|
||||
import { useRemoveRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup';
|
||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
@ -30,12 +29,11 @@ export const AdvancedFilterRuleOptionsDropdown = ({
|
||||
const dropdownId = `advanced-filter-rule-options-${viewFilterId ?? viewFilterGroupId}`;
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
const { deleteCombinedViewFilterGroup } = useDeleteCombinedViewFilterGroup();
|
||||
const { removeRecordFilterGroup } = useRemoveRecordFilterGroup();
|
||||
|
||||
const { currentViewFilterGroup, childViewFiltersAndViewFilterGroups } =
|
||||
useCurrentViewViewFilterGroup({
|
||||
viewFilterGroupId,
|
||||
recordFilterGroupId: viewFilterGroupId,
|
||||
});
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
@ -55,13 +53,11 @@ export const AdvancedFilterRuleOptionsDropdown = ({
|
||||
|
||||
if (
|
||||
isOnlyViewFilterInGroup &&
|
||||
isDefined(currentRecordFilter?.viewFilterGroupId)
|
||||
isDefined(currentRecordFilter?.recordFilterGroupId)
|
||||
) {
|
||||
deleteCombinedViewFilterGroup(currentRecordFilter.viewFilterGroupId);
|
||||
removeRecordFilterGroup(currentRecordFilter.viewFilterGroupId);
|
||||
removeRecordFilterGroup(currentRecordFilter.recordFilterGroupId);
|
||||
}
|
||||
} else if (isDefined(currentViewFilterGroup)) {
|
||||
deleteCombinedViewFilterGroup(currentViewFilterGroup.id);
|
||||
removeRecordFilterGroup(currentViewFilterGroup.id);
|
||||
|
||||
// TODO: This is a temporary fix view filter group will be removed soon.
|
||||
|
||||
@ -67,7 +67,7 @@ export const AdvancedFilterViewFilterFieldSelect = ({
|
||||
}
|
||||
onOpen={() => {
|
||||
setAdvancedFilterViewFilterId(recordFilter?.id);
|
||||
setAdvancedFilterViewFilterGroupId(recordFilter?.viewFilterGroupId);
|
||||
setAdvancedFilterViewFilterGroupId(recordFilter?.recordFilterGroupId);
|
||||
}}
|
||||
dropdownComponents={
|
||||
shouldShowCompositeSelectionSubMenu ? (
|
||||
|
||||
@ -37,7 +37,7 @@ export const AdvancedFilterViewFilterGroup = ({
|
||||
childViewFiltersAndViewFilterGroups,
|
||||
lastChildPosition,
|
||||
} = useCurrentViewViewFilterGroup({
|
||||
viewFilterGroupId,
|
||||
recordFilterGroupId: viewFilterGroupId,
|
||||
});
|
||||
|
||||
if (!currentViewFilterGroup) {
|
||||
@ -46,20 +46,20 @@ export const AdvancedFilterViewFilterGroup = ({
|
||||
|
||||
return (
|
||||
<StyledContainer
|
||||
isGrayBackground={!!currentViewFilterGroup.parentViewFilterGroupId}
|
||||
isGrayBackground={!!currentViewFilterGroup.parentRecordFilterGroupId}
|
||||
>
|
||||
{childViewFiltersAndViewFilterGroups.map((child, i) => (
|
||||
<StyledRow key={child.id}>
|
||||
<AdvancedFilterLogicalOperatorCell
|
||||
index={i}
|
||||
viewFilterGroup={currentViewFilterGroup}
|
||||
recordFilterGroup={currentViewFilterGroup}
|
||||
/>
|
||||
<AdvancedFilterViewFilter viewFilterId={child.id} />
|
||||
<AdvancedFilterRuleOptionsDropdown viewFilterId={child.id} />
|
||||
</StyledRow>
|
||||
))}
|
||||
<AdvancedFilterAddFilterRuleSelect
|
||||
viewFilterGroup={currentViewFilterGroup}
|
||||
recordFilterGroup={currentViewFilterGroup}
|
||||
lastChildPosition={lastChildPosition}
|
||||
/>
|
||||
</StyledContainer>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
|
||||
export const ADVANCED_FILTER_LOGICAL_OPERATOR_OPTIONS = [
|
||||
{
|
||||
value: ViewFilterGroupLogicalOperator.AND,
|
||||
value: RecordFilterGroupLogicalOperator.AND,
|
||||
label: 'And',
|
||||
},
|
||||
{
|
||||
value: ViewFilterGroupLogicalOperator.OR,
|
||||
value: RecordFilterGroupLogicalOperator.OR,
|
||||
label: 'Or',
|
||||
},
|
||||
];
|
||||
|
||||
@ -1,27 +1,28 @@
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useCurrentViewViewFilterGroup = ({
|
||||
viewFilterGroupId,
|
||||
recordFilterGroupId,
|
||||
}: {
|
||||
viewFilterGroupId?: string;
|
||||
recordFilterGroupId?: string;
|
||||
}) => {
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const viewFilterGroup =
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups.find(
|
||||
(viewFilterGroup) => viewFilterGroup.id === viewFilterGroupId,
|
||||
);
|
||||
const currentRecordFilterGroups = useRecoilComponentValueV2(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
if (!isDefined(viewFilterGroup)) {
|
||||
const currentRecordFilterGroup = currentRecordFilterGroups.find(
|
||||
(recordFilterGroup) => recordFilterGroup.id === recordFilterGroupId,
|
||||
);
|
||||
|
||||
if (!isDefined(currentRecordFilterGroup)) {
|
||||
return {
|
||||
currentViewFilterGroup: undefined,
|
||||
childViewFiltersAndViewFilterGroups: [] as (
|
||||
@ -33,31 +34,31 @@ export const useCurrentViewViewFilterGroup = ({
|
||||
|
||||
const childRecordFilters = currentRecordFilters.filter(
|
||||
(recordFilterToFilter) =>
|
||||
recordFilterToFilter.viewFilterGroupId === viewFilterGroup.id,
|
||||
recordFilterToFilter.recordFilterGroupId === currentRecordFilterGroup.id,
|
||||
);
|
||||
|
||||
const childViewFilterGroups =
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups.filter(
|
||||
(viewFilterGroupToFilter) =>
|
||||
viewFilterGroupToFilter.parentViewFilterGroupId === viewFilterGroup.id,
|
||||
);
|
||||
const childViewFilterGroups = currentRecordFilterGroups.filter(
|
||||
(currentRecordGroupToFilter) =>
|
||||
currentRecordGroupToFilter.parentRecordFilterGroupId ===
|
||||
currentRecordFilterGroup.id,
|
||||
);
|
||||
|
||||
const childViewFiltersAndViewFilterGroups = [
|
||||
...(childViewFilterGroups ?? []),
|
||||
...(childRecordFilters ?? []),
|
||||
].sort((a, b) => {
|
||||
const positionA = a.positionInViewFilterGroup ?? 0;
|
||||
const positionB = b.positionInViewFilterGroup ?? 0;
|
||||
const positionA = a.positionInRecordFilterGroup ?? 0;
|
||||
const positionB = b.positionInRecordFilterGroup ?? 0;
|
||||
return positionA - positionB;
|
||||
});
|
||||
|
||||
const lastChildPosition =
|
||||
childViewFiltersAndViewFilterGroups[
|
||||
childViewFiltersAndViewFilterGroups.length - 1
|
||||
]?.positionInViewFilterGroup ?? 0;
|
||||
]?.positionInRecordFilterGroup ?? 0;
|
||||
|
||||
return {
|
||||
currentViewFilterGroup: viewFilterGroup,
|
||||
currentViewFilterGroup: currentRecordFilterGroup,
|
||||
childViewFiltersAndViewFilterGroups,
|
||||
lastChildPosition,
|
||||
};
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useDeleteCombinedViewFilterGroup = (
|
||||
viewBarComponentId?: string,
|
||||
) => {
|
||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterGroupIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const deleteCombinedViewFilterGroup = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (filterGroupId: string) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewIdCallbackState,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilterGroups = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingFilterGroupInCurrentView =
|
||||
currentView.viewFilterGroups?.find(
|
||||
(viewFilterGroup) => viewFilterGroup.id === filterGroupId,
|
||||
);
|
||||
|
||||
const matchingFilterGroupInUnsavedFilterGroups =
|
||||
unsavedToUpsertViewFilterGroups.find(
|
||||
(viewFilterGroup) => viewFilterGroup.id === filterGroupId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingFilterGroupInUnsavedFilterGroups)) {
|
||||
set(
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
unsavedToUpsertViewFilterGroups.filter(
|
||||
(viewFilterGroup) => viewFilterGroup.id !== filterGroupId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isDefined(matchingFilterGroupInCurrentView)) {
|
||||
set(
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
[
|
||||
...new Set([
|
||||
...unsavedToDeleteViewFilterGroupIds,
|
||||
matchingFilterGroupInCurrentView.id,
|
||||
]),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
deleteCombinedViewFilterGroup,
|
||||
};
|
||||
};
|
||||
@ -1,54 +0,0 @@
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useUpsertCombinedViewFilterGroup = () => {
|
||||
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
ViewComponentInstanceContext,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const upsertCombinedViewFilterGroup = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(newViewFilterGroup: Omit<ViewFilterGroup, '__typename'>) => {
|
||||
const currentViewUnsavedToUpsertViewFilterGroups =
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({
|
||||
viewId: newViewFilterGroup.viewId,
|
||||
});
|
||||
|
||||
const unsavedToUpsertViewFilterGroups = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewUnsavedToUpsertViewFilterGroups,
|
||||
);
|
||||
|
||||
const newViewFilterWithTypename: ViewFilterGroup = {
|
||||
...newViewFilterGroup,
|
||||
__typename: 'ViewFilterGroup',
|
||||
};
|
||||
|
||||
set(
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({
|
||||
viewId: newViewFilterGroup.viewId,
|
||||
}),
|
||||
[
|
||||
...unsavedToUpsertViewFilterGroups.filter(
|
||||
(viewFilterGroup) => viewFilterGroup.id !== newViewFilterGroup.id,
|
||||
),
|
||||
newViewFilterWithTypename,
|
||||
],
|
||||
);
|
||||
},
|
||||
[unsavedToUpsertViewFilterGroupsCallbackState],
|
||||
);
|
||||
|
||||
return { upsertCombinedViewFilterGroup };
|
||||
};
|
||||
@ -1,16 +1,17 @@
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
||||
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
|
||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
@ -56,16 +57,13 @@ export const AdvancedFilterButton = () => {
|
||||
OBJECT_FILTER_DROPDOWN_ID,
|
||||
);
|
||||
|
||||
const { currentViewId, currentViewWithCombinedFiltersAndSorts } =
|
||||
useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const { upsertCombinedViewFilterGroup } = useUpsertCombinedViewFilterGroup();
|
||||
const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup();
|
||||
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
|
||||
const objectMetadataId =
|
||||
currentViewWithCombinedFiltersAndSorts?.objectMetadataId;
|
||||
const objectMetadataId = currentView?.objectMetadataId;
|
||||
|
||||
if (!objectMetadataId) {
|
||||
throw new Error('Object metadata id is missing from current view');
|
||||
@ -81,24 +79,24 @@ export const AdvancedFilterButton = () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const currentRecordFilterGroups = useRecoilComponentValueV2(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!currentViewId) {
|
||||
if (!isDefined(currentView)) {
|
||||
throw new Error('Missing current view id');
|
||||
}
|
||||
|
||||
const alreadyHasAdvancedFilterGroup =
|
||||
(currentViewWithCombinedFiltersAndSorts?.viewFilterGroups?.length ?? 0) >
|
||||
0;
|
||||
const alreadyHasAdvancedFilterGroup = currentRecordFilterGroups.length > 0;
|
||||
|
||||
if (!alreadyHasAdvancedFilterGroup) {
|
||||
const newViewFilterGroup = {
|
||||
id: v4(),
|
||||
viewId: currentViewId,
|
||||
viewId: currentView.id,
|
||||
logicalOperator: ViewFilterGroupLogicalOperator.AND,
|
||||
};
|
||||
|
||||
upsertCombinedViewFilterGroup(newViewFilterGroup);
|
||||
|
||||
upsertRecordFilterGroup({
|
||||
id: newViewFilterGroup.id,
|
||||
logicalOperator: RecordFilterGroupLogicalOperator.AND,
|
||||
@ -129,7 +127,7 @@ export const AdvancedFilterButton = () => {
|
||||
operand: firstOperand,
|
||||
value: '',
|
||||
displayValue: '',
|
||||
viewFilterGroupId: newViewFilterGroup.id,
|
||||
recordFilterGroupId: newViewFilterGroup.id,
|
||||
type: getFilterTypeFromFieldType(defaultFieldMetadataItem.type),
|
||||
label: defaultFieldMetadataItem.label,
|
||||
});
|
||||
|
||||
@ -78,7 +78,7 @@ export const ObjectFilterDropdownBooleanSelect = () => {
|
||||
displayValue: value ? 'True' : 'False',
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: value.toString(),
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
});
|
||||
|
||||
@ -59,7 +59,7 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
? newDate.toLocaleString()
|
||||
: newDate.toLocaleDateString()
|
||||
: '',
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
});
|
||||
@ -88,7 +88,7 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: getRelativeDateDisplayValue(relativeDate),
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
});
|
||||
|
||||
@ -18,7 +18,6 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
@ -28,6 +27,7 @@ import { advancedFilterViewFilterIdComponentState } from '@/object-record/object
|
||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const StyledInput = styled.input`
|
||||
@ -156,16 +156,14 @@ export const ObjectFilterDropdownFilterSelect = ({
|
||||
visibleColumnsFieldMetadataItems.length > 0 &&
|
||||
hiddenColumnsFieldMetadataItems.length > 0;
|
||||
|
||||
const { currentViewId, currentViewWithCombinedFiltersAndSorts } =
|
||||
useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const isAdvancedFiltersEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAdvancedFiltersEnabled,
|
||||
);
|
||||
|
||||
const shouldShowAdvancedFilterButton =
|
||||
isDefined(currentViewId) &&
|
||||
isDefined(currentViewWithCombinedFiltersAndSorts?.objectMetadataId) &&
|
||||
isDefined(currentView?.objectMetadataId) &&
|
||||
isAdvancedFilterButtonVisible &&
|
||||
isAdvancedFiltersEnabled;
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
|
||||
displayValue,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItem.type),
|
||||
label: fieldMetadataItem.label,
|
||||
viewFilterGroupId: advancedFilterViewFilterGroupId,
|
||||
recordFilterGroupId: advancedFilterViewFilterGroupId,
|
||||
subFieldName: subFieldName,
|
||||
});
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ export const ObjectFilterDropdownNumberInput = () => {
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -146,7 +146,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: newFilterValue,
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
});
|
||||
}
|
||||
resetSelectedItem();
|
||||
|
||||
@ -65,7 +65,7 @@ export const ObjectFilterDropdownRatingInput = () => {
|
||||
value: convertFieldRatingValueToNumber(newValue),
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: convertFieldRatingValueToNumber(newValue),
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
|
||||
@ -214,7 +214,7 @@ export const ObjectFilterDropdownRecordSelect = ({
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
value: newFilterValue,
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -136,7 +136,7 @@ export const ObjectFilterDropdownSourceSelect = ({
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
value: newFilterValue,
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -64,7 +64,7 @@ export const ObjectFilterDropdownTextSearchInput = () => {
|
||||
value: event.target.value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: event.target.value,
|
||||
viewFilterGroupId: selectedFilter?.viewFilterGroupId,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
|
||||
@ -92,7 +92,7 @@ export const useSelectFilterUsedInDropdown = (componentInstanceId?: string) => {
|
||||
displayValue,
|
||||
operand: firstOperand,
|
||||
value,
|
||||
viewFilterGroupId: advancedFilterViewFilterGroupId,
|
||||
recordFilterGroupId: advancedFilterViewFilterGroupId,
|
||||
type: filterType,
|
||||
label: fieldMetadataItem.label,
|
||||
});
|
||||
|
||||
@ -18,7 +18,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
@ -36,8 +36,7 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
} = useOptionsDropdown();
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
const { currentViewWithCombinedFiltersAndSorts: currentView } =
|
||||
useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const CurrentViewIcon = currentView?.icon ? getIcon(currentView.icon) : null;
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
@ -38,8 +38,7 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
resetContent,
|
||||
} = useOptionsDropdown();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts: currentView } =
|
||||
useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
|
||||
@ -20,6 +20,7 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/s
|
||||
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
|
||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
@ -31,8 +32,8 @@ import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/get
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useScrollRestoration } from '~/hooks/useScrollRestoration';
|
||||
|
||||
@ -104,6 +105,10 @@ export const RecordBoard = () => {
|
||||
const { resetRecordSelection, setRecordAsSelected } =
|
||||
useRecordBoardSelection(recordBoardId);
|
||||
|
||||
const currentRecordSorts = useRecoilComponentValueV2(
|
||||
currentRecordSortsComponentState,
|
||||
);
|
||||
|
||||
useListenClickOutside({
|
||||
excludeClassNames: [
|
||||
'bottom-bar',
|
||||
@ -144,9 +149,6 @@ export const RecordBoard = () => {
|
||||
ActionBarHotkeyScope.ActionBar,
|
||||
);
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } =
|
||||
useGetCurrentView(recordBoardId);
|
||||
|
||||
const setIsRemoveSortingModalOpen = useSetRecoilState(
|
||||
isRemoveSortingModalOpenState,
|
||||
);
|
||||
@ -156,10 +158,7 @@ export const RecordBoard = () => {
|
||||
(result) => {
|
||||
if (!result.destination) return;
|
||||
|
||||
const viewSorts =
|
||||
currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
||||
|
||||
if (viewSorts.length > 0) {
|
||||
if (currentRecordSorts.length > 0) {
|
||||
setIsRemoveSortingModalOpen(true);
|
||||
return;
|
||||
}
|
||||
@ -219,7 +218,7 @@ export const RecordBoard = () => {
|
||||
selectFieldMetadataItem,
|
||||
updateOneRecord,
|
||||
setIsRemoveSortingModalOpen,
|
||||
currentViewWithCombinedFiltersAndSorts,
|
||||
currentRecordSorts,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@ export type RecordFilter = {
|
||||
value: string;
|
||||
displayValue: string;
|
||||
type: FilterableFieldType;
|
||||
viewFilterGroupId?: string;
|
||||
recordFilterGroupId?: string;
|
||||
displayAvatarUrl?: string;
|
||||
operand: ViewFilterOperand;
|
||||
positionInViewFilterGroup?: number | null;
|
||||
positionInRecordFilterGroup?: number | null;
|
||||
label: string;
|
||||
subFieldName?: string | null | undefined;
|
||||
};
|
||||
|
||||
@ -824,7 +824,7 @@ const computeViewFilterGroupRecordGqlOperationFilter = (
|
||||
}
|
||||
|
||||
const groupFilters = filters.filter(
|
||||
(filter) => filter.viewFilterGroupId === currentViewFilterGroupId,
|
||||
(filter) => filter.recordFilterGroupId === currentViewFilterGroupId,
|
||||
);
|
||||
|
||||
const groupRecordGqlOperationFilters = groupFilters
|
||||
@ -886,7 +886,7 @@ export const computeViewRecordGqlOperationFilter = (
|
||||
viewFilterGroups: ViewFilterGroup[],
|
||||
): RecordGqlOperationFilter => {
|
||||
const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = filters
|
||||
.filter((filter) => !filter.viewFilterGroupId)
|
||||
.filter((filter) => !filter.recordFilterGroupId)
|
||||
.map((regularFilter) =>
|
||||
computeFilterRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
|
||||
@ -5,12 +5,13 @@ import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const RecordTableBodyDragDropContextProvider = ({
|
||||
@ -18,7 +19,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
||||
}: {
|
||||
children: ReactNode;
|
||||
}) => {
|
||||
const { objectNameSingular, recordTableId } = useRecordTableContextOrThrow();
|
||||
const { objectNameSingular } = useRecordTableContextOrThrow();
|
||||
|
||||
const { updateOneRecord: updateOneRow } = useUpdateOneRecord({
|
||||
objectNameSingular,
|
||||
@ -28,10 +29,9 @@ export const RecordTableBodyDragDropContextProvider = ({
|
||||
recordIndexAllRecordIdsComponentSelector,
|
||||
);
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } =
|
||||
useGetCurrentView(recordTableId);
|
||||
|
||||
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
||||
const currentRecordSorts = useRecoilComponentValueV2(
|
||||
currentRecordSortsComponentState,
|
||||
);
|
||||
|
||||
const setIsRemoveSortingModalOpen = useSetRecoilState(
|
||||
isRemoveSortingModalOpenState,
|
||||
@ -40,7 +40,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
||||
const handleDragEnd = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(result: DropResult) => {
|
||||
if (viewSorts.length > 0) {
|
||||
if (currentRecordSorts.length > 0) {
|
||||
setIsRemoveSortingModalOpen(true);
|
||||
return;
|
||||
}
|
||||
@ -103,7 +103,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
||||
recordIndexAllRecordIdsSelector,
|
||||
setIsRemoveSortingModalOpen,
|
||||
updateOneRow,
|
||||
viewSorts.length,
|
||||
currentRecordSorts,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -3,28 +3,28 @@ import { useCallback } from 'react';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
|
||||
import { AdvancedFilterRootLevelViewFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRootLevelViewFilterGroup';
|
||||
import { useDeleteCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useDeleteCombinedViewFilterGroup';
|
||||
import { useRemoveRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { AdvancedFilterChip } from '@/views/components/AdvancedFilterChip';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const AdvancedFilterDropdownButton = () => {
|
||||
const { deleteCombinedViewFilterGroup } = useDeleteCombinedViewFilterGroup();
|
||||
const { removeRecordFilterGroup } = useRemoveRecordFilterGroup();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
const currentRecordFilterGroups = useRecoilComponentValueV2(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const advancedRecordFilterIds = currentRecordFilters
|
||||
.filter((recordFilter) => isDefined(recordFilter.viewFilterGroupId))
|
||||
.filter((recordFilter) => isDefined(recordFilter.recordFilterGroupId))
|
||||
.map((recordFilter) => recordFilter.id);
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
@ -39,12 +39,11 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
}
|
||||
|
||||
const viewFilterGroupIds =
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups?.map(
|
||||
(viewFilter) => viewFilter.id,
|
||||
currentRecordFilterGroups?.map(
|
||||
(recordFilterGroup) => recordFilterGroup.id,
|
||||
) ?? [];
|
||||
|
||||
for (const viewFilterGroupId of viewFilterGroupIds) {
|
||||
await deleteCombinedViewFilterGroup(viewFilterGroupId);
|
||||
removeRecordFilterGroup(viewFilterGroupId);
|
||||
}
|
||||
|
||||
@ -55,16 +54,14 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
advancedRecordFilterIds,
|
||||
removeRecordFilterGroup,
|
||||
removeRecordFilter,
|
||||
deleteCombinedViewFilterGroup,
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups,
|
||||
currentRecordFilterGroups,
|
||||
]);
|
||||
|
||||
const outermostViewFilterGroupId =
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups.find(
|
||||
(viewFilterGroup) => !viewFilterGroup.parentViewFilterGroupId,
|
||||
)?.id;
|
||||
const outermostRecordFilterGroupId = currentRecordFilterGroups.find(
|
||||
(recordFilterGroup) => !recordFilterGroup.parentRecordFilterGroupId,
|
||||
)?.id;
|
||||
|
||||
if (!outermostViewFilterGroupId) {
|
||||
if (!outermostRecordFilterGroupId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -79,7 +76,7 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
}
|
||||
dropdownComponents={
|
||||
<AdvancedFilterRootLevelViewFilterGroup
|
||||
rootLevelViewFilterGroupId={outermostViewFilterGroupId}
|
||||
rootLevelViewFilterGroupId={outermostRecordFilterGroupId}
|
||||
/>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: ADVANCED_FILTER_DROPDOWN_ID }}
|
||||
|
||||
@ -2,14 +2,11 @@ import { useEffect } from 'react';
|
||||
|
||||
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
||||
import { useApplyViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyViewFiltersToCurrentRecordFilters';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
|
||||
export const QueryParamsFiltersEffect = () => {
|
||||
const { hasFiltersQueryParams, getFiltersFromQueryParams } =
|
||||
useViewFromQueryParams();
|
||||
|
||||
const { resetUnsavedViewStates } = useResetUnsavedViewStates();
|
||||
|
||||
const { applyViewFiltersToCurrentRecordFilters } =
|
||||
useApplyViewFiltersToCurrentRecordFilters();
|
||||
|
||||
@ -27,7 +24,6 @@ export const QueryParamsFiltersEffect = () => {
|
||||
applyViewFiltersToCurrentRecordFilters,
|
||||
getFiltersFromQueryParams,
|
||||
hasFiltersQueryParams,
|
||||
resetUnsavedViewStates,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
|
||||
@ -19,7 +19,7 @@ import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryP
|
||||
import { useAreViewFilterGroupsDifferentFromRecordFilterGroups } from '@/views/hooks/useAreViewFilterGroupsDifferentFromRecordFilterGroups';
|
||||
import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAreViewFiltersDifferentFromRecordFilters';
|
||||
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
@ -56,7 +56,7 @@ export const UpdateViewButtonGroup = ({
|
||||
const { openDropdown: openViewPickerDropdown } = useDropdown(
|
||||
VIEW_PICKER_DROPDOWN_ID,
|
||||
);
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const setViewPickerReferenceViewId = useSetRecoilComponentStateV2(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
@ -109,7 +109,7 @@ export const UpdateViewButtonGroup = ({
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
{currentViewWithCombinedFiltersAndSorts?.key !== 'INDEX' ? (
|
||||
{currentView?.key !== 'INDEX' ? (
|
||||
<ButtonGroup size="small" accent="blue">
|
||||
<Button title="Update view" onClick={handleUpdateViewClick} />
|
||||
<Dropdown
|
||||
|
||||
@ -53,7 +53,7 @@ export const ViewBar = ({
|
||||
<ViewBarRecordSortEffect />
|
||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||
<QueryParamsFiltersEffect />
|
||||
<ViewBarPageTitle viewBarId={viewBarId} />
|
||||
<ViewBarPageTitle />
|
||||
<TopBar
|
||||
className={className}
|
||||
leftComponent={
|
||||
|
||||
@ -21,8 +21,6 @@ import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '@/views/hooks/
|
||||
import { useApplyCurrentViewSortsToCurrentRecordSorts } from '@/views/hooks/useApplyCurrentViewSortsToCurrentRecordSorts';
|
||||
import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAreViewFiltersDifferentFromRecordFilters';
|
||||
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups } from '@/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups';
|
||||
@ -115,10 +113,6 @@ export const ViewBarDetails = ({
|
||||
viewBarId,
|
||||
objectNamePlural,
|
||||
}: ViewBarDetailsProps) => {
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
|
||||
const viewId = currentViewWithCombinedFiltersAndSorts?.id;
|
||||
|
||||
const isViewBarExpanded = useRecoilComponentValueV2(
|
||||
isViewBarExpandedComponentState,
|
||||
);
|
||||
@ -144,7 +138,6 @@ export const ViewBarDetails = ({
|
||||
objectNameSingular: objectNameSingular,
|
||||
viewBarId: viewBarId,
|
||||
});
|
||||
const { resetUnsavedViewStates } = useResetUnsavedViewStates();
|
||||
|
||||
const { viewFilterGroupsAreDifferentFromRecordFilterGroups } =
|
||||
useAreViewFilterGroupsDifferentFromRecordFilterGroups();
|
||||
@ -170,7 +163,7 @@ export const ViewBarDetails = ({
|
||||
const recordFilters = useMemo(() => {
|
||||
return currentRecordFilters.filter(
|
||||
(recordFilter) =>
|
||||
!recordFilter.viewFilterGroupId &&
|
||||
!recordFilter.recordFilterGroupId &&
|
||||
!checkIsSoftDeleteFilter(recordFilter),
|
||||
);
|
||||
}, [currentRecordFilters, checkIsSoftDeleteFilter]);
|
||||
@ -185,13 +178,10 @@ export const ViewBarDetails = ({
|
||||
useApplyCurrentViewSortsToCurrentRecordSorts();
|
||||
|
||||
const handleCancelClick = () => {
|
||||
if (isDefined(viewId)) {
|
||||
resetUnsavedViewStates(viewId);
|
||||
applyCurrentViewFilterGroupsToCurrentRecordFilterGroups();
|
||||
applyCurrentViewFiltersToCurrentRecordFilters();
|
||||
applyCurrentViewSortsToCurrentRecordSorts();
|
||||
toggleSoftDeleteFilterState(false);
|
||||
}
|
||||
applyCurrentViewFilterGroupsToCurrentRecordFilterGroups();
|
||||
applyCurrentViewFiltersToCurrentRecordFilters();
|
||||
applyCurrentViewSortsToCurrentRecordSorts();
|
||||
toggleSoftDeleteFilterState(false);
|
||||
};
|
||||
|
||||
const shouldExpandViewBar =
|
||||
@ -207,9 +197,8 @@ export const ViewBarDetails = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const showAdvancedFilterDropdownButton =
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups &&
|
||||
currentViewWithCombinedFiltersAndSorts?.viewFilterGroups.length > 0;
|
||||
const shouldShowAdvancedFilterDropdownButton =
|
||||
currentRecordFilterGroups.length > 0;
|
||||
|
||||
return (
|
||||
<StyledBar>
|
||||
@ -239,7 +228,9 @@ export const ViewBarDetails = ({
|
||||
<StyledSeperator />
|
||||
</StyledSeperatorContainer>
|
||||
)}
|
||||
{showAdvancedFilterDropdownButton && <AdvancedFilterDropdownButton />}
|
||||
{shouldShowAdvancedFilterDropdownButton && (
|
||||
<AdvancedFilterDropdownButton />
|
||||
)}
|
||||
{recordFilters.map((recordFilter) => (
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
key={recordFilter.id}
|
||||
|
||||
@ -1,18 +1,13 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { capitalize } from 'twenty-shared';
|
||||
|
||||
export type ViewBarPageTitleProps = {
|
||||
viewBarId: string;
|
||||
};
|
||||
|
||||
export const ViewBarPageTitle = ({ viewBarId }: ViewBarPageTitleProps) => {
|
||||
export const ViewBarPageTitle = () => {
|
||||
const { objectNamePlural } = useParams();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts: currentView } =
|
||||
useGetCurrentView(viewBarId);
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
if (!objectNamePlural) {
|
||||
return;
|
||||
|
||||
@ -104,8 +104,8 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
value: mockViewFilter.value,
|
||||
displayValue: mockViewFilter.displayValue,
|
||||
operand: mockViewFilter.operand,
|
||||
viewFilterGroupId: mockViewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup,
|
||||
recordFilterGroupId: mockViewFilter.viewFilterGroupId,
|
||||
positionInRecordFilterGroup: mockViewFilter.positionInViewFilterGroup,
|
||||
label: mockFieldMetadataItem.label,
|
||||
type: getFilterTypeFromFieldType(mockFieldMetadataItem.type),
|
||||
} satisfies RecordFilter,
|
||||
|
||||
@ -70,8 +70,8 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
||||
value: mockViewFilter.value,
|
||||
displayValue: mockViewFilter.displayValue,
|
||||
operand: mockViewFilter.operand,
|
||||
viewFilterGroupId: mockViewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup,
|
||||
recordFilterGroupId: mockViewFilter.viewFilterGroupId,
|
||||
positionInRecordFilterGroup: mockViewFilter.positionInViewFilterGroup,
|
||||
label: mockFieldMetadataItem.label,
|
||||
type: getFilterTypeFromFieldType(mockFieldMetadataItem.type),
|
||||
} satisfies RecordFilter,
|
||||
|
||||
@ -1,15 +1,10 @@
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { useSetViewInUrl } from '@/views/hooks/useSetViewInUrl';
|
||||
|
||||
export const useChangeView = (viewBarComponentId?: string) => {
|
||||
const { resetUnsavedViewStates } =
|
||||
useResetUnsavedViewStates(viewBarComponentId);
|
||||
|
||||
export const useChangeView = () => {
|
||||
const { setViewInUrl } = useSetViewInUrl();
|
||||
|
||||
const changeView = async (viewId: string) => {
|
||||
setViewInUrl(viewId);
|
||||
resetUnsavedViewStates(viewId);
|
||||
};
|
||||
|
||||
return { changeView };
|
||||
|
||||
@ -2,6 +2,7 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
@ -14,12 +15,12 @@ import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePers
|
||||
import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords';
|
||||
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
|
||||
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
|
||||
import { useGetViewFilterGroupsCombined } from '@/views/hooks/useGetCombinedViewFilterGroups';
|
||||
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup';
|
||||
import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter';
|
||||
import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
@ -39,9 +40,6 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
|
||||
const { createViewFieldRecords } = usePersistViewFieldRecords();
|
||||
|
||||
const { getViewFilterGroupsCombined } =
|
||||
useGetViewFilterGroupsCombined(viewBarComponentId);
|
||||
|
||||
const { createViewSortRecords } = usePersistViewSortRecords();
|
||||
|
||||
const { createViewGroupRecords } = usePersistViewGroupRecords();
|
||||
@ -57,6 +55,10 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
const currentRecordFilterGroups = useRecoilComponentValueV2(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const currentRecordSorts = useRecoilComponentValueV2(
|
||||
currentRecordSortsComponentState,
|
||||
);
|
||||
@ -165,8 +167,12 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
}
|
||||
|
||||
if (shouldCopyFiltersAndSortsAndAggregate === true) {
|
||||
const sourceViewCombinedFilterGroups = getViewFilterGroupsCombined(
|
||||
sourceView.id,
|
||||
const viewFilterGroupsToCreate = currentRecordFilterGroups.map(
|
||||
(recordFilterGroup) =>
|
||||
mapRecordFilterGroupToViewFilterGroup({
|
||||
recordFilterGroup,
|
||||
view: newView,
|
||||
}),
|
||||
);
|
||||
|
||||
const viewSortsToCreate = currentRecordSorts.map(
|
||||
@ -178,10 +184,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
|
||||
await createViewSortRecords(viewSortsToCreate, newView);
|
||||
await createViewFilterRecords(viewFiltersToCreate, newView);
|
||||
await createViewFilterGroupRecords(
|
||||
sourceViewCombinedFilterGroups,
|
||||
newView,
|
||||
);
|
||||
await createViewFilterGroupRecords(viewFilterGroupsToCreate, newView);
|
||||
}
|
||||
|
||||
await findManyRecords();
|
||||
@ -193,13 +196,13 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
createViewFieldRecords,
|
||||
findManyRecords,
|
||||
objectMetadataItem.fields,
|
||||
getViewFilterGroupsCombined,
|
||||
createViewGroupRecords,
|
||||
createViewSortRecords,
|
||||
createViewFilterRecords,
|
||||
createViewFilterGroupRecords,
|
||||
currentRecordFilters,
|
||||
currentRecordSorts,
|
||||
currentRecordFilterGroups,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterGroupIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const getViewFilterGroupsCombined = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new Error(
|
||||
`Cannot get view with id ${viewId}, because it cannot be found in client cache data.`,
|
||||
);
|
||||
}
|
||||
|
||||
const unsavedToUpsertViewFilterGroups = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({ viewId: view.id }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState({ viewId: view.id }),
|
||||
);
|
||||
|
||||
const combinedViewFilterGroups = getCombinedViewFilterGroups(
|
||||
view.viewFilterGroups ?? [],
|
||||
unsavedToUpsertViewFilterGroups,
|
||||
unsavedToDeleteViewFilterGroupIds,
|
||||
);
|
||||
|
||||
return combinedViewFilterGroups;
|
||||
},
|
||||
[
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
getViewFilterGroupsCombined,
|
||||
};
|
||||
};
|
||||
@ -6,14 +6,10 @@ import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefe
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { prefetchViewsFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { isCurrentViewKeyIndexComponentState } from '@/views/states/isCurrentViewIndexComponentState';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
@ -52,7 +48,6 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const viewId = currentViewId ?? indexView?.id;
|
||||
const currentView = currentViewFromViewId ?? indexView;
|
||||
|
||||
useEffect(() => {
|
||||
@ -65,18 +60,6 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
}),
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilterGroups = useRecoilComponentFamilyValueV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
{ viewId },
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterGroupIds = useRecoilComponentFamilyValueV2(
|
||||
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
|
||||
{ viewId },
|
||||
instanceId,
|
||||
);
|
||||
|
||||
if (!isDefined(currentView)) {
|
||||
return {
|
||||
instanceId,
|
||||
@ -86,18 +69,8 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
};
|
||||
}
|
||||
|
||||
const currentViewWithCombinedFiltersAndSorts = {
|
||||
...currentView,
|
||||
viewFilterGroups: getCombinedViewFilterGroups(
|
||||
currentView.viewFilterGroups ?? [],
|
||||
unsavedToUpsertViewFilterGroups,
|
||||
unsavedToDeleteViewFilterGroupIds,
|
||||
),
|
||||
};
|
||||
|
||||
return {
|
||||
instanceId,
|
||||
currentViewWithCombinedFiltersAndSorts,
|
||||
viewsOnCurrentObject: viewsOnCurrentObject ?? [],
|
||||
currentViewId,
|
||||
};
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useResetUnsavedViewStates = (viewBarInstanceId?: string) => {
|
||||
const unsavedToDeleteViewFilterGroupIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const resetUnsavedViewStates = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(viewId: string) => {
|
||||
set(unsavedToDeleteViewFilterGroupIdsCallbackState({ viewId }), []);
|
||||
set(unsavedToUpsertViewFilterGroupsCallbackState({ viewId }), []);
|
||||
},
|
||||
[
|
||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
resetUnsavedViewStates,
|
||||
};
|
||||
};
|
||||
@ -1,131 +1,21 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePersistViewFilterGroupRecords';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { useSaveRecordFilterGroupsToViewFilterGroups } from '@/views/hooks/useSaveRecordFilterGroupsToViewFilterGroups';
|
||||
import { useSaveRecordFiltersToViewFilters } from '@/views/hooks/useSaveRecordFiltersToViewFilters';
|
||||
import { useSaveRecordSortsToViewSorts } from '@/views/hooks/useSaveRecordSortsToViewSorts';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useSaveCurrentViewFiltersAndSorts = (
|
||||
viewBarComponentId?: string,
|
||||
) => {
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterGroupIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const {
|
||||
createViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
updateViewFilterGroupRecords,
|
||||
} = usePersistViewFilterGroupRecords();
|
||||
|
||||
const { resetUnsavedViewStates } =
|
||||
useResetUnsavedViewStates(viewBarComponentId);
|
||||
|
||||
const saveViewFilterGroups = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (viewId: string) => {
|
||||
const unsavedToDeleteViewFilterGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilterGroups = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const view = await getViewFromPrefetchState(viewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewFilterGroupsToCreate = unsavedToUpsertViewFilterGroups.filter(
|
||||
(viewFilterGroup) =>
|
||||
!view.viewFilterGroups?.some(
|
||||
(viewFilterGroupToFilter) =>
|
||||
viewFilterGroupToFilter.id === viewFilterGroup.id,
|
||||
),
|
||||
);
|
||||
|
||||
const viewFilterGroupsToUpdate = unsavedToUpsertViewFilterGroups.filter(
|
||||
(viewFilterGroup) =>
|
||||
view.viewFilterGroups?.some(
|
||||
(viewFilterGroupToFilter) =>
|
||||
viewFilterGroupToFilter.id === viewFilterGroup.id,
|
||||
),
|
||||
);
|
||||
|
||||
await createViewFilterGroupRecords(viewFilterGroupsToCreate, view);
|
||||
await updateViewFilterGroupRecords(viewFilterGroupsToUpdate);
|
||||
await deleteViewFilterGroupRecords(unsavedToDeleteViewFilterGroupIds);
|
||||
},
|
||||
[
|
||||
getViewFromPrefetchState,
|
||||
createViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||
updateViewFilterGroupRecords,
|
||||
],
|
||||
);
|
||||
export const useSaveCurrentViewFiltersAndSorts = () => {
|
||||
const { saveRecordFilterGroupsToViewFilterGroups } =
|
||||
useSaveRecordFilterGroupsToViewFilterGroups();
|
||||
|
||||
const { saveRecordFiltersToViewFilters } =
|
||||
useSaveRecordFiltersToViewFilters();
|
||||
|
||||
const { saveRecordSortsToViewSorts } = useSaveRecordSortsToViewSorts();
|
||||
|
||||
const saveCurrentViewFilterAndSorts = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (viewIdFromProps?: string) => {
|
||||
const currentViewId = snapshot
|
||||
.getLoadable(currentViewIdCallbackState)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewId = viewIdFromProps ?? currentViewId;
|
||||
|
||||
await saveViewFilterGroups(viewId);
|
||||
|
||||
await saveRecordSortsToViewSorts();
|
||||
await saveRecordFiltersToViewFilters();
|
||||
|
||||
resetUnsavedViewStates(viewId);
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
resetUnsavedViewStates,
|
||||
saveViewFilterGroups,
|
||||
saveRecordFiltersToViewFilters,
|
||||
saveRecordSortsToViewSorts,
|
||||
],
|
||||
);
|
||||
const saveCurrentViewFilterAndSorts = async () => {
|
||||
await saveRecordSortsToViewSorts();
|
||||
await saveRecordFiltersToViewFilters();
|
||||
await saveRecordFilterGroupsToViewFilterGroups();
|
||||
};
|
||||
|
||||
return {
|
||||
saveCurrentViewFilterAndSorts,
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePersistViewFilterGroupRecords';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { getViewFilterGroupsToCreate } from '@/views/utils/getViewFilterGroupsToCreate';
|
||||
import { getViewFilterGroupsToDelete } from '@/views/utils/getViewFilterGroupsToDelete';
|
||||
import { getViewFilterGroupsToUpdate } from '@/views/utils/getViewFilterGroupsToUpdate';
|
||||
import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useSaveRecordFilterGroupsToViewFilterGroups = () => {
|
||||
const {
|
||||
createViewFilterGroupRecords,
|
||||
updateViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
} = usePersistViewFilterGroupRecords();
|
||||
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const currentRecordFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(currentRecordFilterGroupsComponentState);
|
||||
|
||||
const saveRecordFilterGroupsToViewFilterGroups = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async () => {
|
||||
if (!isDefined(currentView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentViewFilterGroups = currentView?.viewFilterGroups ?? [];
|
||||
|
||||
const currentRecordFilterGroups = getSnapshotValue(
|
||||
snapshot,
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
);
|
||||
|
||||
const newViewFilterGroups = currentRecordFilterGroups.map(
|
||||
(recordFilterGroup) =>
|
||||
mapRecordFilterGroupToViewFilterGroup({
|
||||
recordFilterGroup,
|
||||
view: currentView,
|
||||
}),
|
||||
);
|
||||
|
||||
const viewFilterGroupsToCreate = getViewFilterGroupsToCreate(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupsToDelete = getViewFilterGroupsToDelete(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterGroupsToUpdate = getViewFilterGroupsToUpdate(
|
||||
currentViewFilterGroups,
|
||||
newViewFilterGroups,
|
||||
);
|
||||
|
||||
const viewFilterIdsToDelete = viewFilterGroupsToDelete.map(
|
||||
(viewFilter) => viewFilter.id,
|
||||
);
|
||||
|
||||
await createViewFilterGroupRecords(
|
||||
viewFilterGroupsToCreate,
|
||||
currentView,
|
||||
);
|
||||
await updateViewFilterGroupRecords(viewFilterGroupsToUpdate);
|
||||
await deleteViewFilterGroupRecords(viewFilterIdsToDelete);
|
||||
},
|
||||
[
|
||||
createViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
updateViewFilterGroupRecords,
|
||||
currentRecordFilterGroupsCallbackState,
|
||||
currentView,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
saveRecordFilterGroupsToViewFilterGroups,
|
||||
};
|
||||
};
|
||||
@ -1,9 +0,0 @@
|
||||
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const unsavedToDeleteViewFilterGroupIdsComponentFamilyState =
|
||||
createComponentFamilyStateV2<string[], { viewId?: string }>({
|
||||
key: 'unsavedToDeleteViewFilterGroupIdsComponentFamilyState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
||||
@ -1,10 +0,0 @@
|
||||
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
|
||||
export const unsavedToUpsertViewFilterGroupsComponentFamilyState =
|
||||
createComponentFamilyStateV2<ViewFilterGroup[], { viewId?: string }>({
|
||||
key: 'unsavedToUpsertViewFilterGroupsComponentFamilyState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
||||
@ -55,6 +55,7 @@ describe('mapViewFiltersToFilters', () => {
|
||||
operand: ViewFilterOperand.Is,
|
||||
},
|
||||
];
|
||||
|
||||
const expectedFilters: RecordFilter[] = [
|
||||
{
|
||||
id: 'id',
|
||||
@ -64,8 +65,8 @@ describe('mapViewFiltersToFilters', () => {
|
||||
operand: ViewFilterOperand.Is,
|
||||
label: baseFieldMetadataItem.label,
|
||||
type: FieldMetadataType.FULL_NAME,
|
||||
positionInViewFilterGroup: undefined,
|
||||
viewFilterGroupId: undefined,
|
||||
positionInRecordFilterGroup: undefined,
|
||||
recordFilterGroupId: undefined,
|
||||
},
|
||||
];
|
||||
expect(
|
||||
|
||||
@ -6,6 +6,12 @@ export const mapRecordFilterToViewFilter = (
|
||||
): ViewFilter => {
|
||||
return {
|
||||
__typename: 'ViewFilter',
|
||||
...recordFilter,
|
||||
} satisfies ViewFilter;
|
||||
displayValue: recordFilter.displayValue,
|
||||
fieldMetadataId: recordFilter.fieldMetadataId,
|
||||
id: recordFilter.id,
|
||||
operand: recordFilter.operand,
|
||||
value: recordFilter.value,
|
||||
positionInViewFilterGroup: recordFilter.positionInRecordFilterGroup,
|
||||
viewFilterGroupId: recordFilter.recordFilterGroupId,
|
||||
};
|
||||
};
|
||||
|
||||
@ -32,11 +32,11 @@ export const mapViewFiltersToFilters = (
|
||||
value: viewFilter.value,
|
||||
displayValue: viewFilter.displayValue,
|
||||
operand: viewFilter.operand,
|
||||
viewFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
recordFilterGroupId: viewFilter.viewFilterGroupId,
|
||||
positionInRecordFilterGroup: viewFilter.positionInViewFilterGroup,
|
||||
label: availableFieldMetadataItem.label,
|
||||
type: filterType,
|
||||
};
|
||||
} satisfies RecordFilter;
|
||||
})
|
||||
.filter(isDefined);
|
||||
};
|
||||
|
||||
@ -1,18 +1,27 @@
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const shouldReplaceFilter = (
|
||||
oldFilter: Pick<RecordFilter, 'id' | 'fieldMetadataId' | 'viewFilterGroupId'>,
|
||||
newFilter: Pick<RecordFilter, 'id' | 'fieldMetadataId' | 'viewFilterGroupId'>,
|
||||
oldFilter: Pick<
|
||||
RecordFilter,
|
||||
'id' | 'fieldMetadataId' | 'recordFilterGroupId'
|
||||
>,
|
||||
newFilter: Pick<
|
||||
RecordFilter,
|
||||
'id' | 'fieldMetadataId' | 'recordFilterGroupId'
|
||||
>,
|
||||
) => {
|
||||
const isNewFilterAdvancedFilter = isDefined(newFilter.viewFilterGroupId);
|
||||
const isNewFilterAdvancedFilter = isDefined(newFilter.recordFilterGroupId);
|
||||
|
||||
if (isNewFilterAdvancedFilter) {
|
||||
return newFilter.id === oldFilter.id;
|
||||
} else {
|
||||
return (
|
||||
newFilter.fieldMetadataId === oldFilter.fieldMetadataId &&
|
||||
!oldFilter.viewFilterGroupId
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
newFilter.fieldMetadataId,
|
||||
oldFilter.fieldMetadataId,
|
||||
) && !isDefined(oldFilter.recordFilterGroupId)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,7 +12,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode';
|
||||
import { ViewPickerContentEditMode } from '@/views/view-picker/components/ViewPickerContentEditMode';
|
||||
@ -51,7 +51,7 @@ const StyledViewName = styled.span`
|
||||
export const ViewPickerDropdown = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const { updateViewFromCurrentState } = useUpdateViewFromCurrentState();
|
||||
|
||||
@ -66,7 +66,7 @@ export const ViewPickerDropdown = () => {
|
||||
const { viewPickerMode, setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
const CurrentViewIcon = getIcon(currentViewWithCombinedFiltersAndSorts?.icon);
|
||||
const CurrentViewIcon = getIcon(currentView?.icon);
|
||||
|
||||
const handleClickOutside = async () => {
|
||||
if (isViewsListDropdownOpen && viewPickerMode === 'edit') {
|
||||
@ -85,14 +85,12 @@ export const ViewPickerDropdown = () => {
|
||||
onClickOutside={handleClickOutside}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer isUnfolded={isViewsListDropdownOpen}>
|
||||
{currentViewWithCombinedFiltersAndSorts && CurrentViewIcon ? (
|
||||
{currentView && CurrentViewIcon ? (
|
||||
<CurrentViewIcon size={theme.icon.size.md} />
|
||||
) : (
|
||||
<IconList size={theme.icon.size.md} />
|
||||
)}
|
||||
<StyledViewName>
|
||||
{currentViewWithCombinedFiltersAndSorts?.name ?? 'All'}
|
||||
</StyledViewName>
|
||||
<StyledViewName>{currentView?.name ?? 'All'}</StyledViewName>
|
||||
<StyledDropdownLabelAdornments>
|
||||
{isDefined(entityCount) && <>· {entityCount} </>}
|
||||
<IconChevronDown size={theme.icon.size.sm} />
|
||||
|
||||
@ -10,13 +10,14 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useChangeView } from '@/views/hooks/useChangeView';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useUpdateView } from '@/views/hooks/useUpdateView';
|
||||
import { ViewPickerOptionDropdown } from '@/views/view-picker/components/ViewPickerOptionDropdown';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { moveArrayItem } from '~/utils/array/moveArrayItem';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
||||
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||
@ -24,8 +25,9 @@ const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
||||
|
||||
export const ViewPickerListContent = () => {
|
||||
const { t } = useLingui();
|
||||
const { currentViewWithCombinedFiltersAndSorts, viewsOnCurrentObject } =
|
||||
useGetCurrentView();
|
||||
const { viewsOnCurrentObject } = useGetCurrentView();
|
||||
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
const setViewPickerReferenceViewId = useSetRecoilComponentStateV2(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
@ -41,8 +43,8 @@ export const ViewPickerListContent = () => {
|
||||
};
|
||||
|
||||
const handleAddViewButtonClick = () => {
|
||||
if (isDefined(currentViewWithCombinedFiltersAndSorts?.id)) {
|
||||
setViewPickerReferenceViewId(currentViewWithCombinedFiltersAndSorts.id);
|
||||
if (isDefined(currentView?.id)) {
|
||||
setViewPickerReferenceViewId(currentView.id);
|
||||
setViewPickerMode('create-empty');
|
||||
}
|
||||
};
|
||||
|
||||
@ -32,7 +32,7 @@ export const useDeleteViewFromCurrentState = (viewBarInstanceId?: string) => {
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const { changeView } = useChangeView(viewBarInstanceId);
|
||||
const { changeView } = useChangeView();
|
||||
|
||||
const { deleteView } = useDeleteView();
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/sta
|
||||
import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useUpdateViewFromCurrentState = (viewBarInstanceId?: string) => {
|
||||
export const useUpdateViewFromCurrentState = () => {
|
||||
const { closeAndResetViewPicker } = useCloseAndResetViewPicker();
|
||||
|
||||
const viewPickerInputNameCallbackState = useRecoilComponentCallbackStateV2(
|
||||
@ -33,7 +33,7 @@ export const useUpdateViewFromCurrentState = (viewBarInstanceId?: string) => {
|
||||
useRecoilComponentCallbackStateV2(viewPickerReferenceViewIdComponentState);
|
||||
|
||||
const { updateView } = useUpdateView();
|
||||
const { changeView } = useChangeView(viewBarInstanceId);
|
||||
const { changeView } = useChangeView();
|
||||
|
||||
const updateViewFromCurrentState = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
|
||||
Reference in New Issue
Block a user