diff --git a/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptionsByLabel.ts b/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptionsByLabel.ts index 1bc747c57a..0c8beeb2a6 100644 --- a/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptionsByLabel.ts +++ b/packages/twenty-front/src/modules/settings/experience/constants/AvailableTimezoneOptionsByLabel.ts @@ -1,4 +1,4 @@ -import { IANA_TIME_ZONES } from '@/localization/constants/IanaTimeZones'; +import { IANA_TIME_ZONES } from 'twenty-shared/constants'; import { formatTimeZoneLabel } from '@/localization/utils/formatTimeZoneLabel'; import { type SelectOption } from 'twenty-ui/input'; diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts index 7e82a1aaf3..bca66e6dff 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts @@ -36,10 +36,10 @@ import { } from 'src/engine/api/common/types/common-query-args.type'; import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type'; import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; -import { GroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-definition.type'; -import { GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; +import { GroupByDefinition } from 'src/engine/api/common/common-query-runners/types/group-by-definition.type'; +import { GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; import { formatResultWithGroupByDimensionValues } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util'; -import { isGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util'; +import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util'; import { parseGroupByArgs } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-args.util'; import { GroupByWithRecordsService } from 'src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service'; import { getGroupLimit } from 'src/engine/api/graphql/graphql-query-runner/group-by/utils/get-group-limit.util'; diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/errors/common-query-runner.exception.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/errors/common-query-runner.exception.ts index 7df5f2b4bb..7a69b0e1cd 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/errors/common-query-runner.exception.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/errors/common-query-runner.exception.ts @@ -18,6 +18,7 @@ export enum CommonQueryRunnerExceptionCode { INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', TOO_COMPLEX_QUERY = 'TOO_COMPLEX_QUERY', MISSING_TIMEZONE_FOR_DATE_GROUP_BY = 'MISSING_TIMEZONE_FOR_DATE_GROUP_BY', + INVALID_TIMEZONE = 'INVALID_TIMEZONE', } export class CommonQueryRunnerException extends CustomException { diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-definition.type.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/types/group-by-definition.type.ts similarity index 100% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-definition.type.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/types/group-by-definition.type.ts diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/types/group-by-field.types.ts similarity index 100% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/types/group-by-field.types.ts diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/__tests__/get-group-by-expression.util.spec.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/__tests__/get-group-by-expression.util.spec.ts new file mode 100644 index 0000000000..958c49d7a1 --- /dev/null +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/__tests__/get-group-by-expression.util.spec.ts @@ -0,0 +1,129 @@ +import { + FieldMetadataType, + ObjectRecordGroupByDateGranularity, +} from 'twenty-shared/types'; + +import { type GroupByDateField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; +import { getGroupByExpression } from 'src/engine/api/common/common-query-runners/utils/get-group-by-expression.util'; +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; + +const buildDateTimeFieldMetadata = (): FlatFieldMetadata => { + return { + type: FieldMetadataType.DATE_TIME, + name: 'createdAt', + } as FlatFieldMetadata; +}; + +const buildGroupByDateField = ( + overrides: Partial = {}, +): GroupByDateField => ({ + fieldMetadata: buildDateTimeFieldMetadata(), + dateGranularity: ObjectRecordGroupByDateGranularity.DAY, + timeZone: 'America/New_York', + ...overrides, +}); + +describe('getGroupByExpression', () => { + const columnNameWithQuotes = '"company"."createdAt"'; + + describe('timezone validation', () => { + it('should accept valid IANA timezones', () => { + const groupByField = buildGroupByDateField({ + timeZone: 'America/New_York', + }); + + const result = getGroupByExpression({ + groupByField, + columnNameWithQuotes, + }); + + expect(result).toContain("'America/New_York'"); + }); + + it('should accept UTC timezone', () => { + const groupByField = buildGroupByDateField({ timeZone: 'UTC' }); + + const result = getGroupByExpression({ + groupByField, + columnNameWithQuotes, + }); + + expect(result).toContain("'UTC'"); + }); + + it('should reject SQL injection in timezone field', () => { + const groupByField = buildGroupByDateField({ + timeZone: "UTC'; DROP TABLE users; --", + }); + + expect(() => + getGroupByExpression({ groupByField, columnNameWithQuotes }), + ).toThrow(); + }); + + it('should reject UNION-based injection in timezone', () => { + const groupByField = buildGroupByDateField({ + timeZone: "UTC') UNION SELECT * FROM pg_shadow --", + }); + + expect(() => + getGroupByExpression({ groupByField, columnNameWithQuotes }), + ).toThrow(); + }); + + it('should reject arbitrary strings as timezone', () => { + const groupByField = buildGroupByDateField({ + timeZone: 'not_a_real_timezone', + }); + + expect(() => + getGroupByExpression({ groupByField, columnNameWithQuotes }), + ).toThrow(); + }); + }); + + describe('missing timezone handling', () => { + it('should throw when timezone is required but not provided', () => { + const groupByField = buildGroupByDateField({ + timeZone: undefined, + }); + + expect(() => + getGroupByExpression({ groupByField, columnNameWithQuotes }), + ).toThrow( + 'Time zone should be specified for a group by date on Day, Week, Month, Quarter or Year', + ); + }); + }); + + describe('granularity without timezone', () => { + it('should return column directly for NONE granularity', () => { + const groupByField = buildGroupByDateField({ + dateGranularity: ObjectRecordGroupByDateGranularity.NONE, + timeZone: undefined, + }); + + const result = getGroupByExpression({ + groupByField, + columnNameWithQuotes, + }); + + expect(result).toBe(columnNameWithQuotes); + }); + + it('should handle DAY_OF_THE_WEEK without timezone', () => { + const groupByField = buildGroupByDateField({ + dateGranularity: ObjectRecordGroupByDateGranularity.DAY_OF_THE_WEEK, + timeZone: undefined, + }); + + const result = getGroupByExpression({ + groupByField, + columnNameWithQuotes, + }); + + expect(result).toContain('TMDay'); + expect(result).not.toContain('AT TIME ZONE'); + }); + }); +}); diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-graphql-api-exception-handler.util.ts index 758c64239c..f4abde80d5 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-graphql-api-exception-handler.util.ts @@ -28,6 +28,7 @@ export const commonQueryRunnerToGraphqlApiExceptionHandler = ( case CommonQueryRunnerExceptionCode.BAD_REQUEST: case CommonQueryRunnerExceptionCode.TOO_COMPLEX_QUERY: case CommonQueryRunnerExceptionCode.MISSING_TIMEZONE_FOR_DATE_GROUP_BY: + case CommonQueryRunnerExceptionCode.INVALID_TIMEZONE: throw new UserInputError(error); case CommonQueryRunnerExceptionCode.INVALID_AUTH_CONTEXT: throw new AuthenticationError(error); diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-rest-api-exception-handler.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-rest-api-exception-handler.util.ts index 7eab629ab2..a1398228e7 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-rest-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/common-query-runner-to-rest-api-exception-handler.util.ts @@ -27,6 +27,7 @@ export const commonQueryRunnerToRestApiExceptionHandler = ( case CommonQueryRunnerExceptionCode.BAD_REQUEST: case CommonQueryRunnerExceptionCode.TOO_COMPLEX_QUERY: case CommonQueryRunnerExceptionCode.MISSING_TIMEZONE_FOR_DATE_GROUP_BY: + case CommonQueryRunnerExceptionCode.INVALID_TIMEZONE: throw new BadRequestException(error.message); case CommonQueryRunnerExceptionCode.RECORD_NOT_FOUND: throw new NotFoundException('Record not found'); diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-definitions.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-definitions.util.ts index f6ca155b59..7d5459acde 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-definitions.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-definitions.util.ts @@ -1,9 +1,9 @@ -import { type GroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-definition.type'; -import { type GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; -import { getGroupByExpression } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-expression.util'; -import { isGroupByDateField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field.util'; -import { isGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util'; -import { formatColumnNameAsAlias } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/remove-quote.util'; +import { type GroupByDefinition } from 'src/engine/api/common/common-query-runners/types/group-by-definition.type'; +import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; +import { getGroupByExpression } from 'src/engine/api/common/common-query-runners/utils/get-group-by-expression.util'; +import { isGroupByDateField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-date-field.util'; +import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util'; +import { formatColumnNameAsAlias } from 'src/engine/api/common/common-query-runners/utils/remove-quote.util'; import { formatColumnNamesFromCompositeFieldAndSubfields } from 'src/engine/twenty-orm/utils/format-column-names-from-composite-field-and-subfield.util'; export const getGroupByDefinitions = ({ diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-expression.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-expression.util.ts similarity index 79% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-expression.util.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-expression.util.ts index 0489eafd9c..e93edd4f4b 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-expression.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-expression.util.ts @@ -1,5 +1,8 @@ import { isNonEmptyString } from '@sniptt/guards'; -import { GROUP_BY_DATE_GRANULARITY_THAT_REQUIRE_TIME_ZONE } from 'twenty-shared/constants'; +import { + GROUP_BY_DATE_GRANULARITY_THAT_REQUIRE_TIME_ZONE, + IANA_TIME_ZONES, +} from 'twenty-shared/constants'; import { FieldMetadataType, ObjectRecordGroupByDateGranularity, @@ -11,9 +14,11 @@ import { CommonQueryRunnerExceptionCode, } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception'; import { STANDARD_ERROR_MESSAGE } from 'src/engine/api/common/common-query-runners/errors/standard-error-message.constant'; -import { type GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; -import { isGroupByDateField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field.util'; -import { isGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util'; +import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; +import { isGroupByDateField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-date-field.util'; +import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util'; + +const VALID_IANA_TIMEZONES = new Set(IANA_TIME_ZONES); export const getGroupByExpression = ({ groupByField, @@ -49,6 +54,18 @@ export const getGroupByExpression = ({ ); } + if ( + shouldUseTimeZone && + !timeZoneIsNotProvided && + !VALID_IANA_TIMEZONES.has(groupByField.timeZone!) + ) { + throw new CommonQueryRunnerException( + `Invalid timezone: ${groupByField.timeZone}`, + CommonQueryRunnerExceptionCode.INVALID_TIMEZONE, + { userFriendlyMessage: STANDARD_ERROR_MESSAGE }, + ); + } + const timeZoneAsDateTruncParameter = shouldUseTimeZone ? `, '${groupByField.timeZone}'` : ''; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-order-expression.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-order-expression.util.ts similarity index 79% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-order-expression.util.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-order-expression.util.ts index fc325e1faa..9e4d1f46eb 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-order-expression.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/get-group-by-order-expression.util.ts @@ -4,10 +4,10 @@ import { } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { type GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; -import { getGroupByExpression } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-expression.util'; -import { isGroupByDateField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field.util'; -import { isGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util'; +import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; +import { getGroupByExpression } from 'src/engine/api/common/common-query-runners/utils/get-group-by-expression.util'; +import { isGroupByDateField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-date-field.util'; +import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util'; const DAYS_OF_WEEK = [ 'Monday', diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/is-group-by-date-field.util.ts similarity index 72% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field.util.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/utils/is-group-by-date-field.util.ts index 2343edda8c..6d17936773 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/is-group-by-date-field.util.ts @@ -1,7 +1,7 @@ import { type GroupByDateField, type GroupByField, -} from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; +} from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; export const isGroupByDateField = ( groupByField: GroupByField, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util.ts similarity index 69% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util.ts index 2c23cac48d..523889dce8 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util.ts @@ -1,7 +1,7 @@ import { type GroupByField, type GroupByRelationField, -} from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; +} from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; export const isGroupByRelationField = ( groupByField: GroupByField, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/remove-quote.util.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/utils/remove-quote.util.ts similarity index 100% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/remove-quote.util.ts rename to packages/twenty-server/src/engine/api/common/common-query-runners/utils/remove-quote.util.ts diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order-group-by.parser.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order-group-by.parser.ts index 9f0c47e869..61e98b0a1d 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order-group-by.parser.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order-group-by.parser.ts @@ -20,8 +20,8 @@ import { type GroupByDateField, type GroupByField, type GroupByRegularField, -} from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; -import { getGroupByOrderExpression } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/get-group-by-order-expression.util'; +} from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; +import { getGroupByOrderExpression } from 'src/engine/api/common/common-query-runners/utils/get-group-by-order-expression.util'; import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper'; import { type AggregationField, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/utils/prepare-for-order-by-relation-field-parsing.util.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/utils/prepare-for-order-by-relation-field-parsing.util.ts index 4cb4d45f58..3eba4d7084 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/utils/prepare-for-order-by-relation-field-parsing.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/utils/prepare-for-order-by-relation-field-parsing.util.ts @@ -5,8 +5,8 @@ import { isDefined } from 'twenty-shared/utils'; import { type GroupByField, type GroupByRelationField, -} from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; -import { isGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-relation-field.util'; +} from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; +import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util'; import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts index 64fcdd4a78..549318f30d 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser.ts @@ -18,7 +18,7 @@ import { GraphqlQuerySelectedFieldsParser, type GraphqlQuerySelectedFieldsResult, } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-selected-fields/graphql-selected-fields.parser'; -import { type GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; +import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util.ts index 50b7445f70..6116b6e19d 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util.ts @@ -6,7 +6,7 @@ import { import { isDefined } from 'twenty-shared/utils'; import { type CommonGroupByOutputItem } from 'src/engine/api/common/types/common-group-by-output-item.type'; -import { type GroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-definition.type'; +import { type GroupByDefinition } from 'src/engine/api/common/common-query-runners/types/group-by-definition.type'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-args.util.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-args.util.ts index e60a2d90a2..b86e3efff1 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-args.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-args.util.ts @@ -3,7 +3,7 @@ import { isDefined } from 'twenty-shared/utils'; import { type GroupByResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -import { type GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; +import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; import { isGroupByDateFieldDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field-definition.util'; import { parseGroupByRelationField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-relation-field.util'; import { validateSingleKeyForGroupByOrThrow } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/validate-single-key-for-group-by-or-throw.util'; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-relation-field.util.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-relation-field.util.ts index 56337d447c..c37f872562 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-relation-field.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-relation-field.util.ts @@ -8,7 +8,7 @@ import { } from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception'; import { type CompositeFieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/composite-field-group-by-definition.type'; import { type DateFieldGroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/date-field-group-by-definition.type'; -import { type GroupByField } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-field.types'; +import { type GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types'; import { isGroupByDateFieldDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/is-group-by-date-field-definition.util'; import { validateSingleKeyForGroupByOrThrow } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/validate-single-key-for-group-by-or-throw.util'; import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service.ts index 578f67bd25..8e71a4651b 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service.ts @@ -14,7 +14,7 @@ import { CommonExtendedQueryRunnerContext } from 'src/engine/api/common/types/co import { type CommonGroupByOutputItem } from 'src/engine/api/common/types/common-group-by-output-item.type'; import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type'; import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; -import { type GroupByDefinition } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/types/group-by-definition.type'; +import { type GroupByDefinition } from 'src/engine/api/common/common-query-runners/types/group-by-definition.type'; import { formatResultWithGroupByDimensionValues } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util'; import { getGroupLimit } from 'src/engine/api/graphql/graphql-query-runner/group-by/utils/get-group-limit.util'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; diff --git a/packages/twenty-front/src/modules/localization/constants/IanaTimeZones.ts b/packages/twenty-shared/src/constants/IanaTimeZones.ts similarity index 99% rename from packages/twenty-front/src/modules/localization/constants/IanaTimeZones.ts rename to packages/twenty-shared/src/constants/IanaTimeZones.ts index d76415c55e..a34acd0d0f 100644 --- a/packages/twenty-front/src/modules/localization/constants/IanaTimeZones.ts +++ b/packages/twenty-shared/src/constants/IanaTimeZones.ts @@ -1,7 +1,5 @@ -/** - * Standard IANA time zones. - * @see https://www.iana.org/time-zones - */ +// Standard IANA time zones +// https://www.iana.org/time-zones export const IANA_TIME_ZONES = [ 'Africa/Abidjan', 'Africa/Accra', diff --git a/packages/twenty-shared/src/constants/index.ts b/packages/twenty-shared/src/constants/index.ts index bb577f02b7..e298d232d2 100644 --- a/packages/twenty-shared/src/constants/index.ts +++ b/packages/twenty-shared/src/constants/index.ts @@ -26,6 +26,7 @@ export { MAX_OPTIONS_TO_DISPLAY } from './FieldMetadataMaxOptionsToDisplay'; export { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from './FieldRestrictedAdditionalPermissionsRequired'; export { FILES_FIELD_MAX_NUMBER_OF_VALUES } from './FilesFieldMaxNumberOfValues'; export { GROUP_BY_DATE_GRANULARITY_THAT_REQUIRE_TIME_ZONE } from './GroupByDateGranularityThatRequireTimeZone'; +export { IANA_TIME_ZONES } from './IanaTimeZones'; export { LABEL_IDENTIFIER_FIELD_METADATA_TYPES } from './LabelIdentifierFieldMetadataTypes'; export { MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES } from './MultiItemFieldDefaultMaxValues'; export { MULTI_ITEM_FIELD_MIN_MAX_VALUES } from './MultiItemFieldMinMaxValues';