[GroupBy] Allow sorting in bar chart (#15097)

Closes https://github.com/twentyhq/core-team-issues/issues/1628

From a technical perspective, we can add more ordering options, such as
the ability to combine two sorts on the X axis, e.g. sort by Close date
ASC and then by Sum ASC, which will sort groups that have the same close
date between themselves depending on their sum ASC. @Bonapara could you
provide design if you want this to be implemented (quite short on our
hand i think - maybe in V2 though)?


https://github.com/user-attachments/assets/6ef21fe1-9d8f-43c0-bfa2-f6fc6341cacf

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
This commit is contained in:
Marie
2025-10-15 14:11:14 +02:00
committed by GitHub
parent 436084f8f4
commit f65783f900
83 changed files with 453 additions and 247 deletions
@@ -2,9 +2,9 @@ import { BadRequestException, Injectable } from '@nestjs/common';
import { type Request } from 'express';
import isEmpty from 'lodash.isempty';
import { type ObjectRecord } from 'twenty-shared/types';
import { In } from 'typeorm';
import { type ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import {
type FormatResult,
RestApiBaseHandler,
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { ObjectRecord } from 'twenty-shared/types';
import {
PageInfo,
RestApiBaseHandler,
@@ -1,8 +1,8 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { ObjectRecord } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler';
import { CommonFindOneQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-find-one-query-runner.service';
@@ -4,16 +4,14 @@ import chunk from 'lodash.chunk';
import isEmpty from 'lodash.isempty';
import {
FieldMetadataType,
ObjectRecord,
type RestrictedFieldsPermissions,
} from 'twenty-shared/types';
import { capitalize, isDefined } from 'twenty-shared/utils';
import { In, type ObjectLiteral } from 'typeorm';
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
import {
type ObjectRecord,
type ObjectRecordFilter,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { type ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
import { encodeCursor } from 'src/engine/api/graphql/graphql-query-runner/utils/cursors.util';
@@ -1,6 +1,6 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { OrderByDirection } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { OrderByDirection } from 'twenty-shared/types';
import {
objectMetadataMapItemMock,
@@ -1,11 +1,9 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { type Request } from 'express';
import { OrderByDirection } from 'twenty-shared/types';
import {
type ObjectRecordOrderBy,
OrderByDirection,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { ObjectRecordOrderBy } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { checkFields } from 'src/engine/api/rest/core/query-builder/utils/check-fields.utils';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
@@ -1,4 +1,4 @@
import { OrderByDirection } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { OrderByDirection } from 'twenty-shared/types';
import { parseOrderByRestRequest } from 'src/engine/api/rest/input-request-parsers/order-by-parser-utils/parse-order-by-rest-request.util';
@@ -1,7 +1,6 @@
import {
type ObjectRecordOrderBy,
OrderByDirection,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { OrderByDirection } from 'twenty-shared/types';
import { type ObjectRecordOrderBy } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
export const addDefaultOrderById = (orderBy: ObjectRecordOrderBy) => {
const hasIdOrder = orderBy.some((o) => Object.keys(o).includes('id'));
@@ -2,10 +2,9 @@
import { BadRequestException } from '@nestjs/common';
import {
type ObjectRecordOrderBy,
OrderByDirection,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { OrderByDirection } from 'twenty-shared/types';
import { type ObjectRecordOrderBy } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
import { DEFAULT_ORDER_DIRECTION } from 'src/engine/api/rest/input-factories/order-by-input.factory';
import { addDefaultOrderById } from 'src/engine/api/rest/input-request-parsers/order-by-parser-utils/add-default-order-by-id.util';