part 4 of filter/sort drilldown onChartDatum click (#16142)
This commit is contained in:
+80
@@ -0,0 +1,80 @@
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { buildDateFilterForDayGranularity } from '../buildDateFilterForDayGranularity';
|
||||
|
||||
describe('buildDateFilterForDayGranularity', () => {
|
||||
describe('DATE field type', () => {
|
||||
it('should return single IS filter with plain date for DATE field', () => {
|
||||
const date = new Date('2024-03-15T10:00:00Z');
|
||||
const result = buildDateFilterForDayGranularity(
|
||||
date,
|
||||
FieldMetadataType.DATE,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].fieldName).toBe('createdAt');
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS);
|
||||
expect(result[0].value).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DATE_TIME field type', () => {
|
||||
it('should return IS_AFTER and IS_BEFORE filters for DATE_TIME field', () => {
|
||||
const date = new Date('2024-03-15T10:00:00Z');
|
||||
const result = buildDateFilterForDayGranularity(
|
||||
date,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
expect(result[0].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
expect(result[1].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
|
||||
it('should apply timezone for DATE_TIME field when provided', () => {
|
||||
const date = new Date('2024-03-15T10:00:00Z');
|
||||
const timezone = 'America/New_York';
|
||||
|
||||
const result = buildDateFilterForDayGranularity(
|
||||
date,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
timezone,
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unsupported field types', () => {
|
||||
it('should return empty array for non-date field types', () => {
|
||||
const date = new Date('2024-03-15T10:00:00Z');
|
||||
const result = buildDateFilterForDayGranularity(
|
||||
date,
|
||||
FieldMetadataType.TEXT as FieldMetadataType.DATE,
|
||||
'name',
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('field name handling', () => {
|
||||
it('should use provided fieldName in filters', () => {
|
||||
const date = new Date('2024-03-15');
|
||||
const result = buildDateFilterForDayGranularity(
|
||||
date,
|
||||
FieldMetadataType.DATE,
|
||||
'customFieldName',
|
||||
);
|
||||
|
||||
expect(result[0].fieldName).toBe('customFieldName');
|
||||
});
|
||||
});
|
||||
});
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
import {
|
||||
ObjectRecordGroupByDateGranularity,
|
||||
ViewFilterOperand,
|
||||
} from 'twenty-shared/types';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { buildDateRangeFiltersForGranularity } from '../buildDateRangeFiltersForGranularity';
|
||||
|
||||
describe('buildDateRangeFiltersForGranularity', () => {
|
||||
describe('WEEK granularity', () => {
|
||||
it('should return IS_AFTER and IS_BEFORE filters for DATE field', () => {
|
||||
const testDate = new Date('2024-03-15');
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.WEEK,
|
||||
FieldMetadataType.DATE,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
|
||||
it('should return ISO strings for DATE_TIME field', () => {
|
||||
const testDate = new Date('2024-03-15T10:00:00Z');
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.WEEK,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
expect(result[1].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('MONTH granularity', () => {
|
||||
it('should return IS_AFTER and IS_BEFORE filters for DATE field', () => {
|
||||
const testDate = new Date('2024-03-15');
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.MONTH,
|
||||
FieldMetadataType.DATE,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
|
||||
it('should return ISO strings for DATE_TIME field without timezone', () => {
|
||||
const testDate = new Date('2024-03-15T10:00:00Z');
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.MONTH,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
expect(result[0].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
expect(result[1].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
|
||||
it('should apply timezone for DATE_TIME field when provided', () => {
|
||||
const testDate = new Date('2024-03-15T10:00:00Z');
|
||||
const timezone = 'America/New_York';
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.MONTH,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
timezone,
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('QUARTER granularity', () => {
|
||||
it('should return filters for Q1 date', () => {
|
||||
const testDate = new Date('2024-02-15');
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.QUARTER,
|
||||
FieldMetadataType.DATE,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
|
||||
it('should return ISO strings for DATE_TIME field', () => {
|
||||
const testDate = new Date('2024-02-15');
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.QUARTER,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
expect(result[0].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
expect(result[1].value).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('YEAR granularity', () => {
|
||||
it('should return start and end of year for DATE field', () => {
|
||||
const testDate = new Date('2024-06-15');
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.YEAR,
|
||||
FieldMetadataType.DATE,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
|
||||
it('should return ISO strings for DATE_TIME field', () => {
|
||||
const testDate = new Date('2024-06-15T10:00:00Z');
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.YEAR,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].value).toMatch(/^2024-01-01T/);
|
||||
expect(result[1].value).toMatch(/^2024-12-31T/);
|
||||
});
|
||||
|
||||
it('should apply timezone for DATE_TIME field', () => {
|
||||
const testDate = new Date('2024-06-15T10:00:00Z');
|
||||
const timezone = 'Asia/Tokyo';
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.YEAR,
|
||||
FieldMetadataType.DATE_TIME,
|
||||
'createdAt',
|
||||
timezone,
|
||||
);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].operand).toBe(ViewFilterOperand.IS_AFTER);
|
||||
expect(result[1].operand).toBe(ViewFilterOperand.IS_BEFORE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Field name handling', () => {
|
||||
it('should use provided fieldName in filters', () => {
|
||||
const testDate = new Date('2024-03-15');
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.MONTH,
|
||||
FieldMetadataType.DATE,
|
||||
'customFieldName',
|
||||
);
|
||||
|
||||
expect(result[0].fieldName).toBe('customFieldName');
|
||||
expect(result[1].fieldName).toBe('customFieldName');
|
||||
});
|
||||
|
||||
it('should handle subField-style fieldName', () => {
|
||||
const testDate = new Date('2024-03-15');
|
||||
|
||||
const result = buildDateRangeFiltersForGranularity(
|
||||
testDate,
|
||||
ObjectRecordGroupByDateGranularity.MONTH,
|
||||
FieldMetadataType.DATE,
|
||||
'parent.subField',
|
||||
);
|
||||
|
||||
expect(result[0].fieldName).toBe('parent.subField');
|
||||
expect(result[1].fieldName).toBe('parent.subField');
|
||||
});
|
||||
});
|
||||
});
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
import { calculateQuarterDateRange } from '../calculateQuarterDateRange';
|
||||
|
||||
describe('calculateQuarterDateRange', () => {
|
||||
describe('Q1 (January - March)', () => {
|
||||
it('should return Q1 range for January date', () => {
|
||||
const date = new Date('2024-01-15');
|
||||
const result = calculateQuarterDateRange(date);
|
||||
|
||||
expect(result.rangeStartDate.getFullYear()).toBe(2024);
|
||||
expect(result.rangeStartDate.getMonth()).toBe(0);
|
||||
expect(result.rangeStartDate.getDate()).toBe(1);
|
||||
|
||||
expect(result.rangeEndDate.getFullYear()).toBe(2024);
|
||||
expect(result.rangeEndDate.getMonth()).toBe(2);
|
||||
expect(result.rangeEndDate.getDate()).toBe(31);
|
||||
});
|
||||
|
||||
it('should return Q1 range for March date', () => {
|
||||
const date = new Date('2024-03-20');
|
||||
const result = calculateQuarterDateRange(date);
|
||||
|
||||
expect(result.rangeStartDate.getMonth()).toBe(0);
|
||||
expect(result.rangeEndDate.getMonth()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Q2 (April - June)', () => {
|
||||
it('should return Q2 range for April date', () => {
|
||||
const date = new Date('2024-04-15');
|
||||
const result = calculateQuarterDateRange(date);
|
||||
|
||||
expect(result.rangeStartDate.getMonth()).toBe(3);
|
||||
expect(result.rangeStartDate.getDate()).toBe(1);
|
||||
expect(result.rangeEndDate.getMonth()).toBe(5);
|
||||
expect(result.rangeEndDate.getDate()).toBe(30);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Q3 (July - September)', () => {
|
||||
it('should return Q3 range for August date', () => {
|
||||
const date = new Date('2024-08-15');
|
||||
const result = calculateQuarterDateRange(date);
|
||||
|
||||
expect(result.rangeStartDate.getMonth()).toBe(6);
|
||||
expect(result.rangeStartDate.getDate()).toBe(1);
|
||||
expect(result.rangeEndDate.getMonth()).toBe(8);
|
||||
expect(result.rangeEndDate.getDate()).toBe(30);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Q4 (October - December)', () => {
|
||||
it('should return Q4 range for November date', () => {
|
||||
const date = new Date('2024-11-15');
|
||||
const result = calculateQuarterDateRange(date);
|
||||
|
||||
expect(result.rangeStartDate.getMonth()).toBe(9);
|
||||
expect(result.rangeStartDate.getDate()).toBe(1);
|
||||
expect(result.rangeEndDate.getMonth()).toBe(11);
|
||||
expect(result.rangeEndDate.getDate()).toBe(31);
|
||||
});
|
||||
});
|
||||
|
||||
describe('year boundary', () => {
|
||||
it('should handle year correctly for Q1', () => {
|
||||
const date = new Date('2025-02-15');
|
||||
const result = calculateQuarterDateRange(date);
|
||||
|
||||
expect(result.rangeStartDate.getFullYear()).toBe(2025);
|
||||
expect(result.rangeEndDate.getFullYear()).toBe(2025);
|
||||
});
|
||||
});
|
||||
});
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
import { TZDate } from '@date-fns/tz';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import {
|
||||
getEndUnitOfDateTime,
|
||||
getPlainDateFromDate,
|
||||
getStartUnitOfDateTime,
|
||||
} from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
type ChartFilter = {
|
||||
fieldName: string;
|
||||
operand: ViewFilterOperand;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export const buildDateFilterForDayGranularity = (
|
||||
parsedBucketDate: Date,
|
||||
fieldType: FieldMetadataType,
|
||||
fieldName: string,
|
||||
timezone?: string,
|
||||
): ChartFilter[] => {
|
||||
if (fieldType === FieldMetadataType.DATE) {
|
||||
return [
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: getPlainDateFromDate(parsedBucketDate),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (fieldType === FieldMetadataType.DATE_TIME) {
|
||||
const dateInTimezone = timezone
|
||||
? new TZDate(parsedBucketDate, timezone)
|
||||
: parsedBucketDate;
|
||||
|
||||
const startOfDayDate = getStartUnitOfDateTime(dateInTimezone, 'DAY');
|
||||
const endOfDayDate = getEndUnitOfDateTime(dateInTimezone, 'DAY');
|
||||
|
||||
return [
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS_AFTER,
|
||||
value: startOfDayDate.toISOString(),
|
||||
},
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS_BEFORE,
|
||||
value: endOfDayDate.toISOString(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
import { buildFiltersFromDateRange } from '@/page-layout/widgets/graph/utils/buildFiltersFromDateRange';
|
||||
import { calculateQuarterDateRange } from '@/page-layout/widgets/graph/utils/calculateQuarterDateRange';
|
||||
import { TZDate } from '@date-fns/tz';
|
||||
import {
|
||||
ObjectRecordGroupByDateGranularity,
|
||||
type ViewFilterOperand,
|
||||
} from 'twenty-shared/types';
|
||||
import {
|
||||
getEndUnitOfDateTime,
|
||||
getStartUnitOfDateTime,
|
||||
} from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export type RangeChartFilter = {
|
||||
fieldName: string;
|
||||
operand: ViewFilterOperand;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export const buildDateRangeFiltersForGranularity = (
|
||||
parsedBucketDate: Date,
|
||||
dateGranularity: ObjectRecordGroupByDateGranularity,
|
||||
fieldType: FieldMetadataType,
|
||||
fieldName: string,
|
||||
timezone?: string,
|
||||
): RangeChartFilter[] => {
|
||||
const dateInTimezone =
|
||||
fieldType === FieldMetadataType.DATE_TIME && timezone
|
||||
? new TZDate(parsedBucketDate, timezone)
|
||||
: parsedBucketDate;
|
||||
|
||||
if (dateGranularity === ObjectRecordGroupByDateGranularity.WEEK) {
|
||||
return buildFiltersFromDateRange(
|
||||
getStartUnitOfDateTime(dateInTimezone, 'WEEK'),
|
||||
getEndUnitOfDateTime(dateInTimezone, 'WEEK'),
|
||||
fieldType,
|
||||
fieldName,
|
||||
);
|
||||
}
|
||||
|
||||
if (dateGranularity === ObjectRecordGroupByDateGranularity.MONTH) {
|
||||
return buildFiltersFromDateRange(
|
||||
getStartUnitOfDateTime(dateInTimezone, 'MONTH'),
|
||||
getEndUnitOfDateTime(dateInTimezone, 'MONTH'),
|
||||
fieldType,
|
||||
fieldName,
|
||||
);
|
||||
}
|
||||
|
||||
if (dateGranularity === ObjectRecordGroupByDateGranularity.QUARTER) {
|
||||
const quarterRange = calculateQuarterDateRange(dateInTimezone, timezone);
|
||||
|
||||
return buildFiltersFromDateRange(
|
||||
quarterRange.rangeStartDate,
|
||||
quarterRange.rangeEndDate,
|
||||
fieldType,
|
||||
fieldName,
|
||||
);
|
||||
}
|
||||
|
||||
return buildFiltersFromDateRange(
|
||||
getStartUnitOfDateTime(dateInTimezone, 'YEAR'),
|
||||
getEndUnitOfDateTime(dateInTimezone, 'YEAR'),
|
||||
fieldType,
|
||||
fieldName,
|
||||
);
|
||||
};
|
||||
+51
-4
@@ -1,11 +1,19 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { buildDateFilterForDayGranularity } from '@/page-layout/widgets/graph/utils/buildDateFilterForDayGranularity';
|
||||
import { buildDateRangeFiltersForGranularity } from '@/page-layout/widgets/graph/utils/buildDateRangeFiltersForGranularity';
|
||||
import { isCyclicalDateGranularity } from '@/page-layout/widgets/graph/utils/isCyclicalDateGranularity';
|
||||
import { isTimeRangeDateGranularity } from '@/page-layout/widgets/graph/utils/isTimeRangeDateGranularity';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
ObjectRecordGroupByDateGranularity,
|
||||
ViewFilterOperand,
|
||||
type ObjectRecordGroupByDateGranularity,
|
||||
} from 'twenty-shared/types';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
getFilterTypeFromFieldType,
|
||||
isDefined,
|
||||
isFieldMetadataDateKind,
|
||||
} from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
type ChartFilter = {
|
||||
@@ -17,9 +25,9 @@ type ChartFilter = {
|
||||
type BuildFilterFromChartBucketParams = {
|
||||
fieldMetadataItem: FieldMetadataItem;
|
||||
bucketRawValue: unknown;
|
||||
dateGranularity?: ObjectRecordGroupByDateGranularity | null; // TODO: Will be used for date filtering
|
||||
dateGranularity?: ObjectRecordGroupByDateGranularity | null;
|
||||
subFieldName?: string | null;
|
||||
timezone?: string; // TODO: Will be used for date filtering
|
||||
timezone?: string;
|
||||
};
|
||||
|
||||
const formatChartFilterValue = (
|
||||
@@ -43,7 +51,9 @@ const formatChartFilterValue = (
|
||||
export const buildFilterFromChartBucket = ({
|
||||
fieldMetadataItem,
|
||||
bucketRawValue,
|
||||
dateGranularity,
|
||||
subFieldName,
|
||||
timezone,
|
||||
}: BuildFilterFromChartBucketParams): ChartFilter[] => {
|
||||
const fieldName = isNonEmptyString(subFieldName)
|
||||
? `${fieldMetadataItem.name}.${subFieldName}`
|
||||
@@ -59,6 +69,43 @@ export const buildFilterFromChartBucket = ({
|
||||
];
|
||||
}
|
||||
|
||||
if (isFieldMetadataDateKind(fieldMetadataItem.type)) {
|
||||
const parsedBucketDate = new Date(String(bucketRawValue));
|
||||
|
||||
if (isNaN(parsedBucketDate.getTime())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (isCyclicalDateGranularity(dateGranularity)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (
|
||||
!isDefined(dateGranularity) ||
|
||||
dateGranularity === ObjectRecordGroupByDateGranularity.DAY ||
|
||||
dateGranularity === ObjectRecordGroupByDateGranularity.NONE
|
||||
) {
|
||||
return buildDateFilterForDayGranularity(
|
||||
parsedBucketDate,
|
||||
fieldMetadataItem.type,
|
||||
fieldName,
|
||||
timezone,
|
||||
);
|
||||
}
|
||||
|
||||
if (isTimeRangeDateGranularity(dateGranularity)) {
|
||||
return buildDateRangeFiltersForGranularity(
|
||||
parsedBucketDate,
|
||||
dateGranularity,
|
||||
fieldMetadataItem.type,
|
||||
fieldName,
|
||||
timezone,
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const availableOperands = getRecordFilterOperands({
|
||||
filterType: getFilterTypeFromFieldType(fieldMetadataItem.type),
|
||||
subFieldName: subFieldName ?? undefined,
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { type RangeChartFilter } from '@/page-layout/widgets/graph/utils/buildDateRangeFiltersForGranularity';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { getPlainDateFromDate } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const buildFiltersFromDateRange = (
|
||||
rangeStartDate: Date,
|
||||
rangeEndDate: Date,
|
||||
fieldType: FieldMetadataType,
|
||||
fieldName: string,
|
||||
): RangeChartFilter[] => {
|
||||
if (fieldType === FieldMetadataType.DATE_TIME) {
|
||||
return [
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS_AFTER,
|
||||
value: rangeStartDate.toISOString(),
|
||||
},
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS_BEFORE,
|
||||
value: rangeEndDate.toISOString(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS_AFTER,
|
||||
value: getPlainDateFromDate(rangeStartDate),
|
||||
},
|
||||
{
|
||||
fieldName,
|
||||
operand: ViewFilterOperand.IS_BEFORE,
|
||||
value: getPlainDateFromDate(rangeEndDate),
|
||||
},
|
||||
];
|
||||
};
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import { TZDate } from '@date-fns/tz';
|
||||
import { getEndUnitOfDateTime } from 'twenty-shared/utils';
|
||||
|
||||
type QuarterDateRange = {
|
||||
rangeStartDate: Date;
|
||||
rangeEndDate: Date;
|
||||
};
|
||||
|
||||
export const calculateQuarterDateRange = (
|
||||
parsedBucketDate: Date,
|
||||
timezone?: string,
|
||||
): QuarterDateRange => {
|
||||
const quarterStartMonthIndex =
|
||||
Math.floor(parsedBucketDate.getMonth() / 3) * 3;
|
||||
const rangeStartDate = timezone
|
||||
? new TZDate(
|
||||
parsedBucketDate.getFullYear(),
|
||||
quarterStartMonthIndex,
|
||||
1,
|
||||
timezone,
|
||||
)
|
||||
: new Date(parsedBucketDate.getFullYear(), quarterStartMonthIndex, 1);
|
||||
|
||||
const quarterFinalMonthIndex = quarterStartMonthIndex + 2;
|
||||
const rangeEndDate = getEndUnitOfDateTime(
|
||||
timezone
|
||||
? new TZDate(
|
||||
parsedBucketDate.getFullYear(),
|
||||
quarterFinalMonthIndex,
|
||||
1,
|
||||
timezone,
|
||||
)
|
||||
: new Date(parsedBucketDate.getFullYear(), quarterFinalMonthIndex, 1),
|
||||
'MONTH',
|
||||
);
|
||||
|
||||
return { rangeStartDate, rangeEndDate };
|
||||
};
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const isCyclicalDateGranularity = (
|
||||
granularity?: ObjectRecordGroupByDateGranularity | null,
|
||||
): boolean => {
|
||||
if (!isDefined(granularity)) return false;
|
||||
return [
|
||||
ObjectRecordGroupByDateGranularity.DAY_OF_THE_WEEK,
|
||||
ObjectRecordGroupByDateGranularity.MONTH_OF_THE_YEAR,
|
||||
ObjectRecordGroupByDateGranularity.QUARTER_OF_THE_YEAR,
|
||||
].includes(granularity);
|
||||
};
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const isTimeRangeDateGranularity = (
|
||||
granularity?: ObjectRecordGroupByDateGranularity | null,
|
||||
): boolean => {
|
||||
if (!isDefined(granularity)) return false;
|
||||
return [
|
||||
ObjectRecordGroupByDateGranularity.WEEK,
|
||||
ObjectRecordGroupByDateGranularity.MONTH,
|
||||
ObjectRecordGroupByDateGranularity.QUARTER,
|
||||
ObjectRecordGroupByDateGranularity.YEAR,
|
||||
].includes(granularity);
|
||||
};
|
||||
Reference in New Issue
Block a user