Aggregate queries follow up (#9581)
In this PR - fixing Collapse on view groups views: aggregate bar should be included in the collapse (@magrinj ) - respect the html table pattern: the aggregate bar is now a <tr> element included in a <table> (before that, it was a <tr> not included in anything) - add a top-border on the aggregate bar - introduce short labels for the on-cell value display (display "Empty" instead of "Count empty" to lighten the interface) - remove the feature flag !
This commit is contained in:
@ -389,7 +389,6 @@ export type FeatureFlagFilter = {
|
||||
|
||||
export enum FeatureFlagKey {
|
||||
IsAdvancedFiltersEnabled = 'IsAdvancedFiltersEnabled',
|
||||
IsAggregateQueryEnabled = 'IsAggregateQueryEnabled',
|
||||
IsAirtableIntegrationEnabled = 'IsAirtableIntegrationEnabled',
|
||||
IsAnalyticsV2Enabled = 'IsAnalyticsV2Enabled',
|
||||
IsCommandMenuV2Enabled = 'IsCommandMenuV2Enabled',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
import { gql } from '@apollo/client';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
@ -321,7 +321,6 @@ export type FeatureFlagFilter = {
|
||||
|
||||
export enum FeatureFlagKey {
|
||||
IsAdvancedFiltersEnabled = 'IsAdvancedFiltersEnabled',
|
||||
IsAggregateQueryEnabled = 'IsAggregateQueryEnabled',
|
||||
IsAirtableIntegrationEnabled = 'IsAirtableIntegrationEnabled',
|
||||
IsAnalyticsV2Enabled = 'IsAnalyticsV2Enabled',
|
||||
IsCommandMenuV2Enabled = 'IsCommandMenuV2Enabled',
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
import { getAggregateQueryName } from '@/object-record/utils/getAggregateQueryName';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
@ -8,16 +7,6 @@ jest.mock('@apollo/client', () => ({
|
||||
useApolloClient: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@/workspace/hooks/useIsFeatureEnabled', () => ({
|
||||
useIsFeatureEnabled: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('~/generated/graphql', () => ({
|
||||
FeatureFlagKey: {
|
||||
IsAggregateQueryEnabled: 'IsAggregateQueryEnabled',
|
||||
},
|
||||
}));
|
||||
|
||||
describe('useRefetchAggregateQueries', () => {
|
||||
const mockRefetchQueries = jest.fn();
|
||||
const mockApolloClient = {
|
||||
@ -29,9 +18,8 @@ describe('useRefetchAggregateQueries', () => {
|
||||
(useApolloClient as jest.Mock).mockReturnValue(mockApolloClient);
|
||||
});
|
||||
|
||||
it('should refetch queries when feature flag is enabled', async () => {
|
||||
it('should refetch queries', async () => {
|
||||
// Arrange
|
||||
(useIsFeatureEnabled as jest.Mock).mockReturnValue(true);
|
||||
const objectMetadataNamePlural = 'opportunities';
|
||||
const expectedQueryName = getAggregateQueryName(objectMetadataNamePlural);
|
||||
|
||||
@ -48,24 +36,8 @@ describe('useRefetchAggregateQueries', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not refetch queries when feature flag is disabled', async () => {
|
||||
// Arrange
|
||||
(useIsFeatureEnabled as jest.Mock).mockReturnValue(false);
|
||||
const objectMetadataNamePlural = 'opportunities';
|
||||
|
||||
// Act
|
||||
const { result } = renderHook(() =>
|
||||
useRefetchAggregateQueries({ objectMetadataNamePlural }),
|
||||
);
|
||||
await result.current.refetchAggregateQueries();
|
||||
|
||||
// Assert
|
||||
expect(mockRefetchQueries).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle errors during refetch', async () => {
|
||||
// Arrange
|
||||
(useIsFeatureEnabled as jest.Mock).mockReturnValue(true);
|
||||
const error = new Error('Refetch failed');
|
||||
mockRefetchQueries.mockRejectedValue(error);
|
||||
const objectMetadataNamePlural = 'opportunities';
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import { getAggregateQueryName } from '@/object-record/utils/getAggregateQueryName';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
export const useRefetchAggregateQueries = ({
|
||||
objectMetadataNamePlural,
|
||||
@ -9,17 +7,13 @@ export const useRefetchAggregateQueries = ({
|
||||
objectMetadataNamePlural: string;
|
||||
}) => {
|
||||
const apolloClient = useApolloClient();
|
||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
);
|
||||
const refetchAggregateQueries = async () => {
|
||||
if (isAggregateQueryEnabled) {
|
||||
const queryName = getAggregateQueryName(objectMetadataNamePlural);
|
||||
|
||||
await apolloClient.refetchQueries({
|
||||
include: [queryName],
|
||||
});
|
||||
}
|
||||
const refetchAggregateQueries = async () => {
|
||||
const queryName = getAggregateQueryName(objectMetadataNamePlural);
|
||||
|
||||
await apolloClient.refetchQueries({
|
||||
include: [queryName],
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -44,7 +44,6 @@ export const RecordBoardColumn = ({
|
||||
<RecordBoardColumnContext.Provider
|
||||
value={{
|
||||
columnDefinition: recordGroupDefinition,
|
||||
recordCount: recordIdsByGroup.length,
|
||||
columnId: recordBoardColumnId,
|
||||
recordIds: recordIdsByGroup,
|
||||
}}
|
||||
|
||||
@ -12,9 +12,7 @@ import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-b
|
||||
import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope';
|
||||
import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { IconDotsVertical, IconPlus, LightIconButton, Tag } from 'twenty-ui';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
const StyledHeader = styled.div`
|
||||
align-items: center;
|
||||
@ -42,16 +40,6 @@ const StyledLeftContainer = styled.div`
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledRecordCountChildren = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
height: 24px;
|
||||
justify-content: center;
|
||||
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||
width: 22px;
|
||||
`;
|
||||
|
||||
const StyledRightContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@ -103,10 +91,6 @@ export const RecordBoardColumnHeader = () => {
|
||||
columnDefinition.id ?? '',
|
||||
);
|
||||
|
||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
);
|
||||
|
||||
const { isOpportunitiesCompanyFieldDisabled } =
|
||||
useIsOpportunitiesCompanyFieldDisabled();
|
||||
|
||||
@ -141,18 +125,12 @@ export const RecordBoardColumnHeader = () => {
|
||||
: 'medium'
|
||||
}
|
||||
/>
|
||||
{isAggregateQueryEnabled ? (
|
||||
<RecordBoardColumnHeaderAggregateDropdown
|
||||
aggregateValue={aggregateValue}
|
||||
dropdownId={`record-board-column-aggregate-dropdown-${columnDefinition.id}`}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
aggregateLabel={aggregateLabel}
|
||||
/>
|
||||
) : (
|
||||
<StyledRecordCountChildren>
|
||||
{aggregateValue}
|
||||
</StyledRecordCountChildren>
|
||||
)}
|
||||
<RecordBoardColumnHeaderAggregateDropdown
|
||||
aggregateValue={aggregateValue}
|
||||
dropdownId={`record-board-column-aggregate-dropdown-${columnDefinition.id}`}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
aggregateLabel={aggregateLabel}
|
||||
/>
|
||||
</StyledLeftContainer>
|
||||
<StyledRightContainer>
|
||||
{isHeaderHovered && (
|
||||
|
||||
@ -32,7 +32,6 @@ export const RecordBoardColumnHeaderWrapper = ({
|
||||
value={{
|
||||
columnId,
|
||||
columnDefinition: recordGroupDefinition,
|
||||
recordCount: recordIdsByGroup.length,
|
||||
recordIds: recordIdsByGroup,
|
||||
}}
|
||||
>
|
||||
|
||||
@ -4,7 +4,6 @@ import { RecordGroupDefinition } from '@/object-record/record-group/types/Record
|
||||
|
||||
type RecordBoardColumnContextProps = {
|
||||
columnDefinition: RecordGroupDefinition;
|
||||
recordCount: number;
|
||||
columnId: string;
|
||||
recordIds: string[];
|
||||
};
|
||||
|
||||
@ -10,20 +10,12 @@ import { recordIndexKanbanAggregateOperationState } from '@/object-record/record
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||
import { UserContext } from '@/users/contexts/UserContext';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useAggregateRecordsForRecordBoardColumn = () => {
|
||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
);
|
||||
|
||||
const { columnDefinition, recordCount } = useContext(
|
||||
RecordBoardColumnContext,
|
||||
);
|
||||
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||
|
||||
const { objectMetadataItem } = useContext(RecordBoardContext);
|
||||
|
||||
@ -78,7 +70,6 @@ export const useAggregateRecordsForRecordBoardColumn = () => {
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
recordGqlFieldsAggregate,
|
||||
filter,
|
||||
skip: !isAggregateQueryEnabled,
|
||||
});
|
||||
|
||||
const { dateFormat, timeFormat, timeZone } = useContext(UserContext);
|
||||
@ -95,7 +86,7 @@ export const useAggregateRecordsForRecordBoardColumn = () => {
|
||||
});
|
||||
|
||||
return {
|
||||
aggregateValue: isAggregateQueryEnabled ? value : recordCount,
|
||||
aggregateValue: value,
|
||||
aggregateLabel: isDefined(value) ? labelWithFieldName : undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -171,7 +171,7 @@ describe('computeAggregateValueAndLabel', () => {
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
label: 'Earliest date',
|
||||
label: 'Earliest',
|
||||
labelWithFieldName: 'Earliest date of Created At',
|
||||
value: '1 Jan, 2023 12:00',
|
||||
});
|
||||
@ -207,7 +207,7 @@ describe('computeAggregateValueAndLabel', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
value: '31 Dec, 2023 23:59',
|
||||
label: 'Latest date',
|
||||
label: 'Latest',
|
||||
labelWithFieldName: 'Latest date of Updated At',
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,6 +3,7 @@ import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { AggregateRecordsData } from '@/object-record/hooks/useAggregateRecords';
|
||||
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
|
||||
import { getAggregateOperationShortLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel';
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { COUNT_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/countAggregateOperationOptions';
|
||||
import { PERCENT_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/percentAggregateOperationOptions';
|
||||
@ -118,7 +119,7 @@ export const computeAggregateValueAndLabel = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
const label = getAggregateOperationLabel(aggregateOperation);
|
||||
const label = getAggregateOperationShortLabel(aggregateOperation);
|
||||
const labelWithFieldName =
|
||||
aggregateOperation === AGGREGATE_OPERATIONS.count
|
||||
? `${getAggregateOperationLabel(AGGREGATE_OPERATIONS.count)}`
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { DATE_AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/DateAggregateOperations';
|
||||
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
|
||||
export const getAggregateOperationShortLabel = (
|
||||
operation: ExtendedAggregateOperations,
|
||||
) => {
|
||||
switch (operation) {
|
||||
case AGGREGATE_OPERATIONS.min:
|
||||
return 'Min';
|
||||
case AGGREGATE_OPERATIONS.max:
|
||||
return 'Max';
|
||||
case AGGREGATE_OPERATIONS.avg:
|
||||
return 'Average';
|
||||
case AGGREGATE_OPERATIONS.sum:
|
||||
return 'Sum';
|
||||
case AGGREGATE_OPERATIONS.count:
|
||||
return 'All';
|
||||
case AGGREGATE_OPERATIONS.countEmpty:
|
||||
case AGGREGATE_OPERATIONS.percentageEmpty:
|
||||
return 'Empty';
|
||||
case AGGREGATE_OPERATIONS.countNotEmpty:
|
||||
case AGGREGATE_OPERATIONS.percentageNotEmpty:
|
||||
return 'Not empty';
|
||||
case AGGREGATE_OPERATIONS.countUniqueValues:
|
||||
return 'Unique';
|
||||
case DATE_AGGREGATE_OPERATIONS.earliest:
|
||||
return 'Earliest';
|
||||
case DATE_AGGREGATE_OPERATIONS.latest:
|
||||
return 'Latest';
|
||||
default:
|
||||
throw new Error(`Unknown aggregate operation: ${operation}`);
|
||||
}
|
||||
};
|
||||
@ -13,16 +13,13 @@ import { RecordTableNoRecordGroupBody } from '@/object-record/record-table/recor
|
||||
import { RecordTableNoRecordGroupBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect';
|
||||
import { RecordTableRecordGroupBodyEffects } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects';
|
||||
import { RecordTableRecordGroupsBody } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody';
|
||||
import { RecordTableAggregateFooter } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooter';
|
||||
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { hasPendingRecordComponentSelector } from '@/object-record/record-table/states/selectors/hasPendingRecordComponentSelector';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useRef } from 'react';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
const StyledTable = styled.table`
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
@ -36,10 +33,6 @@ export const RecordTable = () => {
|
||||
|
||||
const tableBodyRef = useRef<HTMLTableElement>(null);
|
||||
|
||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
);
|
||||
|
||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||
RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID,
|
||||
);
|
||||
@ -97,12 +90,6 @@ export const RecordTable = () => {
|
||||
<RecordTableRecordGroupsBody />
|
||||
)}
|
||||
<RecordTableStickyEffect />
|
||||
{isAggregateQueryEnabled &&
|
||||
!hasRecordGroups &&
|
||||
!isRecordTableInitialLoading &&
|
||||
allRecordIds.length > 0 && (
|
||||
<RecordTableAggregateFooter endOfTableSticky />
|
||||
)}
|
||||
</StyledTable>
|
||||
<DragSelect
|
||||
dragSelectable={tableBodyRef}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader';
|
||||
import { RecordTableAggregateFooter } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooter';
|
||||
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordTableNoRecordGroupRows = () => {
|
||||
@ -8,6 +10,10 @@ export const RecordTableNoRecordGroupRows = () => {
|
||||
recordIndexAllRecordIdsComponentSelector,
|
||||
);
|
||||
|
||||
const isRecordTableInitialLoading = useRecoilComponentValueV2(
|
||||
isRecordTableInitialLoadingComponentState,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{allRecordIds.map((recordId, rowIndex) => {
|
||||
@ -21,6 +27,9 @@ export const RecordTableNoRecordGroupRows = () => {
|
||||
);
|
||||
})}
|
||||
<RecordTableBodyFetchMoreLoader />
|
||||
{!isRecordTableInitialLoading && allRecordIds.length > 0 && (
|
||||
<RecordTableAggregateFooter endOfTableSticky />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { RecordTableAggregateFooter } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooter';
|
||||
import { RecordTablePendingRecordGroupRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRecordGroupRow';
|
||||
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
|
||||
import { RecordTableRecordGroupSectionAddNew } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew';
|
||||
@ -59,6 +60,10 @@ export const RecordTableRecordGroupRows = () => {
|
||||
<RecordTablePendingRecordGroupRow />
|
||||
<RecordTableRecordGroupSectionAddNew />
|
||||
<RecordTableRecordGroupSectionLoadMore />
|
||||
<RecordTableAggregateFooter
|
||||
key={currentRecordGroupId}
|
||||
currentRecordGroupId={currentRecordGroupId}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -6,14 +6,11 @@ import { RecordTableRecordGroupRows } from '@/object-record/record-table/compone
|
||||
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
||||
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
|
||||
import { RecordTableBodyRecordGroupDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider';
|
||||
import { RecordTableAggregateFooter } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooter';
|
||||
import { RecordTableRecordGroupSection } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
export const RecordTableRecordGroupsBody = () => {
|
||||
const allRecordIds = useRecoilComponentValueV2(
|
||||
@ -29,10 +26,6 @@ export const RecordTableRecordGroupsBody = () => {
|
||||
ViewType.Table,
|
||||
);
|
||||
|
||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
);
|
||||
|
||||
if (isRecordTableInitialLoading && allRecordIds.length === 0) {
|
||||
return <RecordTableBodyLoading />;
|
||||
}
|
||||
@ -50,12 +43,6 @@ export const RecordTableRecordGroupsBody = () => {
|
||||
<RecordTableRecordGroupSection />
|
||||
<RecordTableRecordGroupRows />
|
||||
</RecordTableBodyDroppable>
|
||||
{isAggregateQueryEnabled && (
|
||||
<RecordTableAggregateFooter
|
||||
key={recordGroupId}
|
||||
currentRecordGroupId={recordGroupId}
|
||||
/>
|
||||
)}
|
||||
</RecordGroupContext.Provider>
|
||||
</RecordTableRecordGroupBodyContextProvider>
|
||||
))}
|
||||
|
||||
@ -8,38 +8,41 @@ import { scrollWrapperInstanceComponentState } from '@/ui/utilities/scroll/state
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
||||
|
||||
const StyledTh = styled.th`
|
||||
const StyledTd = styled.td`
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
`;
|
||||
|
||||
const StyledTableFoot = styled.thead<{
|
||||
const StyledTableRow = styled.tr<{
|
||||
endOfTableSticky?: boolean;
|
||||
hasHorizontalOverflow?: boolean;
|
||||
}>`
|
||||
td {
|
||||
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
}
|
||||
cursor: pointer;
|
||||
th:nth-of-type(1) {
|
||||
td:nth-of-type(1) {
|
||||
width: ${FIRST_TH_WIDTH};
|
||||
left: 0;
|
||||
border-right-color: ${({ theme }) => theme.background.primary};
|
||||
border-top: none;
|
||||
}
|
||||
th:nth-of-type(2) {
|
||||
td:nth-of-type(2) {
|
||||
border-right-color: ${({ theme }) => theme.background.primary};
|
||||
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
}
|
||||
&.first-columns-sticky {
|
||||
th:nth-of-type(1) {
|
||||
td:nth-of-type(1) {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
transition: 0.3s ease;
|
||||
}
|
||||
th:nth-of-type(2) {
|
||||
td:nth-of-type(2) {
|
||||
position: sticky;
|
||||
left: 11px;
|
||||
z-index: 5;
|
||||
transition: 0.3s ease;
|
||||
}
|
||||
th:nth-of-type(3) {
|
||||
td:nth-of-type(3) {
|
||||
position: sticky;
|
||||
left: 43px;
|
||||
z-index: 5;
|
||||
@ -60,13 +63,12 @@ const StyledTableFoot = styled.thead<{
|
||||
}
|
||||
}
|
||||
}
|
||||
tr {
|
||||
position: sticky;
|
||||
z-index: 5;
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
${({ endOfTableSticky, hasHorizontalOverflow }) =>
|
||||
endOfTableSticky &&
|
||||
`
|
||||
position: sticky;
|
||||
z-index: 5;
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
${({ endOfTableSticky, hasHorizontalOverflow }) =>
|
||||
endOfTableSticky &&
|
||||
`
|
||||
bottom: ${hasHorizontalOverflow ? '10px' : '0'};
|
||||
${
|
||||
hasHorizontalOverflow &&
|
||||
@ -83,7 +85,6 @@ const StyledTableFoot = styled.thead<{
|
||||
`
|
||||
}
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
||||
export const RecordTableAggregateFooter = ({
|
||||
@ -108,32 +109,30 @@ export const RecordTableAggregateFooter = ({
|
||||
: false;
|
||||
|
||||
return (
|
||||
<StyledTableFoot
|
||||
<StyledTableRow
|
||||
id={`record-table-footer${currentRecordGroupId ? '-' + currentRecordGroupId : ''}`}
|
||||
data-select-disable
|
||||
endOfTableSticky={endOfTableSticky}
|
||||
hasHorizontalOverflow={hasHorizontalOverflow}
|
||||
>
|
||||
<tr>
|
||||
<StyledTh />
|
||||
<StyledTh />
|
||||
{visibleTableColumns.map((column, index) => {
|
||||
return (
|
||||
<RecordTableColumnAggregateFooterCellContext.Provider
|
||||
key={`${column.fieldMetadataId}${currentRecordGroupId ? '-' + currentRecordGroupId : ''}`}
|
||||
value={{
|
||||
viewFieldId: column.viewFieldId || '',
|
||||
fieldMetadataId: column.fieldMetadataId,
|
||||
}}
|
||||
>
|
||||
<RecordTableAggregateFooterCell
|
||||
currentRecordGroupId={currentRecordGroupId}
|
||||
isFirstCell={index === 0}
|
||||
/>
|
||||
</RecordTableColumnAggregateFooterCellContext.Provider>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</StyledTableFoot>
|
||||
<StyledTd />
|
||||
<StyledTd />
|
||||
{visibleTableColumns.map((column, index) => {
|
||||
return (
|
||||
<RecordTableColumnAggregateFooterCellContext.Provider
|
||||
key={`${column.fieldMetadataId}${currentRecordGroupId ? '-' + currentRecordGroupId : ''}`}
|
||||
value={{
|
||||
viewFieldId: column.viewFieldId || '',
|
||||
fieldMetadataId: column.fieldMetadataId,
|
||||
}}
|
||||
>
|
||||
<RecordTableAggregateFooterCell
|
||||
currentRecordGroupId={currentRecordGroupId}
|
||||
isFirstCell={index === 0}
|
||||
/>
|
||||
</RecordTableColumnAggregateFooterCellContext.Provider>
|
||||
);
|
||||
})}
|
||||
</StyledTableRow>
|
||||
);
|
||||
};
|
||||
|
||||
@ -9,7 +9,7 @@ import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
||||
|
||||
const COLUMN_MIN_WIDTH = 104;
|
||||
|
||||
const StyledColumnFooterCell = styled.th<{
|
||||
const StyledColumnFooterCell = styled.td<{
|
||||
columnWidth: number;
|
||||
}>`
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
@ -43,7 +43,6 @@ const StyledColumnFooterCell = styled.th<{
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
`;
|
||||
|
||||
const StyledColumnFootContainer = styled.div`
|
||||
|
||||
@ -9,18 +9,13 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte
|
||||
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||
import { UserContext } from '@/users/contexts/UserContext';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useAggregateRecordsForRecordTableColumnFooter = (
|
||||
fieldMetadataId: string,
|
||||
) => {
|
||||
const isAggregateQueryEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
);
|
||||
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||
const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields);
|
||||
|
||||
@ -61,8 +56,7 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
recordGqlFieldsAggregate,
|
||||
filter: { ...requestFilters, ...recordGroupFilter },
|
||||
skip:
|
||||
!isAggregateQueryEnabled || !isDefined(aggregateOperationForViewField),
|
||||
skip: !isDefined(aggregateOperationForViewField),
|
||||
});
|
||||
|
||||
const { dateFormat, timeFormat, timeZone } = useContext(UserContext);
|
||||
|
||||
@ -6,6 +6,10 @@ const StyledTr = styled.tr<{ isDragging: boolean }>`
|
||||
? `1px solid ${theme.border.color.medium}`
|
||||
: '1px solid transparent'};
|
||||
transition: border-left-color 0.2s ease-in-out;
|
||||
|
||||
&:nth-last-child(2) td {
|
||||
border-bottom: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export const RecordTableTr = StyledTr;
|
||||
|
||||
@ -70,11 +70,6 @@ export const seedFeatureFlags = async (
|
||||
workspaceId: workspaceId,
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||
workspaceId: workspaceId,
|
||||
|
||||
@ -27,7 +27,6 @@ import {
|
||||
getCursor,
|
||||
getPaginationInfo,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
import { isDefined } from 'src/utils/is-defined';
|
||||
@ -109,19 +108,6 @@ export class GraphqlQueryFindManyResolverService extends GraphqlQueryBaseResolve
|
||||
appliedFilters,
|
||||
);
|
||||
|
||||
const isAggregationsEnabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsAggregateQueryEnabled,
|
||||
authContext.workspace.id,
|
||||
);
|
||||
|
||||
if (!isAggregationsEnabled) {
|
||||
executionArgs.graphqlQuerySelectedFieldsResult.aggregate = {
|
||||
totalCount:
|
||||
executionArgs.graphqlQuerySelectedFieldsResult.aggregate.totalCount,
|
||||
};
|
||||
}
|
||||
|
||||
const processAggregateHelper = new ProcessAggregateHelper();
|
||||
|
||||
processAggregateHelper.addSelectedAggregatedFieldsQueriesToQueryBuilder({
|
||||
|
||||
@ -12,7 +12,6 @@ export enum FeatureFlagKey {
|
||||
IsUniqueIndexesEnabled = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IsMicrosoftSyncEnabled = 'IS_MICROSOFT_SYNC_ENABLED',
|
||||
IsAdvancedFiltersEnabled = 'IS_ADVANCED_FILTERS_ENABLED',
|
||||
IsAggregateQueryEnabled = 'IS_AGGREGATE_QUERY_ENABLED',
|
||||
IsCommandMenuV2Enabled = 'IS_COMMAND_MENU_V2_ENABLED',
|
||||
IsCrmMigrationEnabled = 'IS_CRM_MIGRATION_ENABLED',
|
||||
IsJsonFilterEnabled = 'IS_JSON_FILTER_ENABLED',
|
||||
|
||||
Reference in New Issue
Block a user