Fix kanban view picker total count (#10898)
Fixes https://github.com/twentyhq/twenty/issues/9790 Before https://github.com/user-attachments/assets/332ec338-ce87-4d4d-ac47-a4e76dceb5b0 After https://github.com/user-attachments/assets/93a03842-386a-4e75-a709-85a91bbc7679 --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -15,7 +15,7 @@ export type AggregateRecordsData = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAggregateRecords = ({
|
export const useAggregateRecords = <T extends AggregateRecordsData>({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
filter,
|
filter,
|
||||||
recordGqlFieldsAggregate,
|
recordGqlFieldsAggregate,
|
||||||
@ -63,7 +63,7 @@ export const useAggregateRecords = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
data: formattedData,
|
data: formattedData as T,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter';
|
import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter';
|
||||||
import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort';
|
import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort';
|
||||||
import { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||||
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
|
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
|
||||||
@ -21,7 +20,6 @@ export const RecordIndexTableContainerEffect = () => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
setOnEntityCountChange,
|
|
||||||
setOnToggleColumnFilter,
|
setOnToggleColumnFilter,
|
||||||
setOnToggleColumnSort,
|
setOnToggleColumnSort,
|
||||||
} = useRecordTable({
|
} = useRecordTable({
|
||||||
@ -35,8 +33,6 @@ export const RecordIndexTableContainerEffect = () => {
|
|||||||
const { columnDefinitions } =
|
const { columnDefinitions } =
|
||||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||||
|
|
||||||
const { setRecordIndexEntityCount } = useSetRecordIndexEntityCount(viewBarId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAvailableTableColumns(columnDefinitions);
|
setAvailableTableColumns(columnDefinitions);
|
||||||
}, [columnDefinitions, setAvailableTableColumns]);
|
}, [columnDefinitions, setAvailableTableColumns]);
|
||||||
@ -66,13 +62,6 @@ export const RecordIndexTableContainerEffect = () => {
|
|||||||
);
|
);
|
||||||
}, [setOnToggleColumnSort, handleToggleColumnSort]);
|
}, [setOnToggleColumnSort, handleToggleColumnSort]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOnEntityCountChange(
|
|
||||||
() => (entityCount: number, currentRecordGroupId?: string) =>
|
|
||||||
setRecordIndexEntityCount(entityCount, currentRecordGroupId),
|
|
||||||
);
|
|
||||||
}, [setRecordIndexEntityCount, setOnEntityCountChange]);
|
|
||||||
|
|
||||||
const setViewFieldAggregateOperation = useRecoilCallback(
|
const setViewFieldAggregateOperation = useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
(viewField: ViewField) => {
|
(viewField: ViewField) => {
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
|||||||
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeRecordGqlOperationFilter } 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';
|
||||||
import { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
|
||||||
|
|
||||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
@ -88,7 +87,6 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
fetchMoreRecords,
|
fetchMoreRecords,
|
||||||
queryStateIdentifier,
|
queryStateIdentifier,
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
totalCount,
|
|
||||||
} = useFindManyRecords({
|
} = useFindManyRecords({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
filter,
|
filter,
|
||||||
@ -97,13 +95,6 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
limit: 10,
|
limit: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setRecordIndexEntityCount } =
|
|
||||||
useSetRecordIndexEntityCount(recordBoardId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setRecordIndexEntityCount(totalCount ?? 0, columnId);
|
|
||||||
}, [setRecordIndexEntityCount, totalCount, columnId]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRecordIdsForColumn(columnId, records);
|
setRecordIdsForColumn(columnId, records);
|
||||||
}, [records, setRecordIdsForColumn, columnId]);
|
}, [records, setRecordIdsForColumn, columnId]);
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
import { recordIndexEntityCountByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexEntityCountByGroupComponentFamilyState';
|
|
||||||
import { recordIndexEntityCountNoGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexEntityCountNoGroupComponentFamilyState';
|
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
export const useSetRecordIndexEntityCount = (viewBarComponentId?: string) => {
|
|
||||||
const recordIndexEntityCountNoGroupFamilyState =
|
|
||||||
useRecoilComponentCallbackStateV2(
|
|
||||||
recordIndexEntityCountNoGroupComponentFamilyState,
|
|
||||||
viewBarComponentId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordIndexEntityCountByGroupFamilyState =
|
|
||||||
useRecoilComponentCallbackStateV2(
|
|
||||||
recordIndexEntityCountByGroupComponentFamilyState,
|
|
||||||
viewBarComponentId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setRecordIndexEntityCount = useRecoilCallback(
|
|
||||||
({ set }) =>
|
|
||||||
(count: number, recordGroupId?: string) => {
|
|
||||||
if (isDefined(recordGroupId)) {
|
|
||||||
set(recordIndexEntityCountByGroupFamilyState(recordGroupId), count);
|
|
||||||
} else {
|
|
||||||
set(recordIndexEntityCountNoGroupFamilyState, count);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
recordIndexEntityCountByGroupFamilyState,
|
|
||||||
recordIndexEntityCountNoGroupFamilyState,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
setRecordIndexEntityCount,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
|
||||||
|
|
||||||
export const recordIndexEntityCountNoGroupComponentFamilyState =
|
|
||||||
createComponentStateV2<number | undefined>({
|
|
||||||
key: 'recordIndexEntityCountNoGroupComponentFamilyState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
componentInstanceContext: ViewComponentInstanceContext,
|
|
||||||
});
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
|
||||||
import { recordIndexEntityCountByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexEntityCountByGroupComponentFamilyState';
|
|
||||||
import { recordIndexEntityCountNoGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexEntityCountNoGroupComponentFamilyState';
|
|
||||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
|
||||||
|
|
||||||
export const recordIndexEntityCountComponentSelector =
|
|
||||||
createComponentSelectorV2<number | undefined>({
|
|
||||||
key: 'recordIndexEntityCountComponentSelector',
|
|
||||||
get:
|
|
||||||
({ instanceId }) =>
|
|
||||||
({ get }) => {
|
|
||||||
const recordGroupIds = get(
|
|
||||||
recordGroupIdsComponentState.atomFamily({
|
|
||||||
instanceId,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (recordGroupIds.length === 0) {
|
|
||||||
return get(
|
|
||||||
recordIndexEntityCountNoGroupComponentFamilyState.atomFamily({
|
|
||||||
instanceId,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return recordGroupIds.reduce<number>((acc, recordGroupId) => {
|
|
||||||
const count = get(
|
|
||||||
recordIndexEntityCountByGroupComponentFamilyState.atomFamily({
|
|
||||||
instanceId,
|
|
||||||
familyKey: recordGroupId,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return acc + (count ?? 0);
|
|
||||||
}, 0);
|
|
||||||
},
|
|
||||||
componentInstanceContext: ViewComponentInstanceContext,
|
|
||||||
});
|
|
||||||
@ -4,7 +4,6 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo
|
|||||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||||
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 { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
||||||
@ -30,7 +29,7 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { setAvailableTableColumns, setOnEntityCountChange } = useRecordTable({
|
const { setAvailableTableColumns } = useRecordTable({
|
||||||
recordTableId,
|
recordTableId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -47,8 +46,6 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
const { setAvailableFieldDefinitions, setViewObjectMetadataId } =
|
const { setAvailableFieldDefinitions, setViewObjectMetadataId } =
|
||||||
useInitViewBar(viewId);
|
useInitViewBar(viewId);
|
||||||
|
|
||||||
const { setRecordIndexEntityCount } = useSetRecordIndexEntityCount(viewId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setViewObjectMetadataId?.(objectMetadataItem.id);
|
setViewObjectMetadataId?.(objectMetadataItem.id);
|
||||||
|
|
||||||
@ -75,11 +72,5 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
setContextStoreCurrentObjectMetadataItemId,
|
setContextStoreCurrentObjectMetadataItemId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOnEntityCountChange(
|
|
||||||
() => (entityCount: number) => setRecordIndexEntityCount(entityCount),
|
|
||||||
);
|
|
||||||
}, [setRecordIndexEntityCount, setOnEntityCountChange]);
|
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||||
|
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
|
||||||
|
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
|
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
|
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
|
export const useGetRecordIndexTotalCount = () => {
|
||||||
|
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
|
||||||
|
|
||||||
|
const currentRecordFilterGroups = useRecoilComponentValueV2(
|
||||||
|
currentRecordFilterGroupsComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentRecordFilters = useRecoilComponentValueV2(
|
||||||
|
currentRecordFiltersComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
|
const filter = computeRecordGqlOperationFilter({
|
||||||
|
filterValueDependencies,
|
||||||
|
recordFilters: currentRecordFilters,
|
||||||
|
recordFilterGroups: currentRecordFilterGroups,
|
||||||
|
fields: objectMetadataItem.fields,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data, loading } = useAggregateRecords<{
|
||||||
|
id: { COUNT: number };
|
||||||
|
}>({
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
filter,
|
||||||
|
recordGqlFieldsAggregate: {
|
||||||
|
id: [AGGREGATE_OPERATIONS.count],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalCount = data?.id?.COUNT;
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalCount,
|
||||||
|
loading,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -7,11 +7,10 @@ import {
|
|||||||
useIcons,
|
useIcons,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
import { recordIndexEntityCountComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexEntityCountComponentSelector';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
|
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useGetRecordIndexTotalCount } from '@/views/hooks/internal/useGetRecordIndexTotalCount';
|
||||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||||
import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode';
|
import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode';
|
||||||
@ -55,9 +54,7 @@ export const ViewPickerDropdown = () => {
|
|||||||
|
|
||||||
const { updateViewFromCurrentState } = useUpdateViewFromCurrentState();
|
const { updateViewFromCurrentState } = useUpdateViewFromCurrentState();
|
||||||
|
|
||||||
const entityCount = useRecoilComponentValueV2(
|
const { totalCount } = useGetRecordIndexTotalCount();
|
||||||
recordIndexEntityCountComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { isDropdownOpen: isViewsListDropdownOpen } = useDropdown(
|
const { isDropdownOpen: isViewsListDropdownOpen } = useDropdown(
|
||||||
VIEW_PICKER_DROPDOWN_ID,
|
VIEW_PICKER_DROPDOWN_ID,
|
||||||
@ -92,7 +89,7 @@ export const ViewPickerDropdown = () => {
|
|||||||
)}
|
)}
|
||||||
<StyledViewName>{currentView?.name ?? 'All'}</StyledViewName>
|
<StyledViewName>{currentView?.name ?? 'All'}</StyledViewName>
|
||||||
<StyledDropdownLabelAdornments>
|
<StyledDropdownLabelAdornments>
|
||||||
{isDefined(entityCount) && <>· {entityCount} </>}
|
{isDefined(totalCount) && <>· {totalCount} </>}
|
||||||
<IconChevronDown size={theme.icon.size.sm} />
|
<IconChevronDown size={theme.icon.size.sm} />
|
||||||
</StyledDropdownLabelAdornments>
|
</StyledDropdownLabelAdornments>
|
||||||
</StyledDropdownButtonContainer>
|
</StyledDropdownButtonContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user