feat(page-layout): add number format option to aggregate chart widget (#21521)

## Context
Closes #21522
Large values in the dashboard **Number** widget are always abbreviated
(e.g. `1300090` → `1.3m`) with no way to display the full number.
Following a discussion with the core team who were interested in this
feature
(https://discordapp.com/channels/1130383047699738754/1509604545381142649)
, this adds a **Format** option in the **Style** section of the Number
(aggregate chart) widget, letting users choose between **Short**
(abbreviated, current behavior) and **Full** (complete number with
thousand separators).

Only the displayed value of the Number widget is affected — axes, labels
and tooltips of other chart types are intentionally left untouched.

## What's inside

**Server**
- New `ChartNumberFormat` GraphQL enum (`SHORT` / `FULL`), following the
`AxisNameDisplay` pattern
- The existing — and previously unused — `format` field on
`AggregateChartConfigurationDTO` is now typed with this enum and
validated with `@IsEnum`
- The dashboard AI tool schema (`widget.schema.ts`) accepts the new
`format` option
- Regenerated GraphQL types and the `twenty-client-sdk` metadata client
to reflect the enum

**Front**
- New **Format** setting in the Style section of the Number widget
settings, with a Short/Full selection dropdown (same pattern as the Axis
name setting)
- `transformAggregateRawValueIntoAggregateDisplayValue` takes an
optional `numberFormat`:
- `FULL` → full number via `formatNumber` (currency values keep up to 2
decimals)
  - `SHORT` → abbreviated via `formatToShortNumber`
- not set → behavior unchanged (currency short, number full), so
existing widgets and the record table/board footers render exactly as
before

## Screenshots

| Full UI Look | 

<img width="1917" height="955" alt="Twenty_Showcas_FullShort"
src="https://github.com/user-attachments/assets/05d05779-395d-4e1a-8ff0-964f6fbef182"
/>

| Menu UI Look |
<img width="291" height="308" alt="Screenshot_2"
src="https://github.com/user-attachments/assets/82b5a1de-32fe-46ec-a9b8-add11ab4c6cd"
/>
 

## Tests

- Extended `transformAggregateRawValueIntoAggregateDisplayValue` unit
tests with SHORT/FULL cases for currency and number fields
- Updated the page-layout-widget creation/update integration tests and
snapshots to use `ChartNumberFormat.SHORT`


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21521?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Alexandre Ribeiro
2026-06-13 17:32:41 -04:00
committed by GitHub
parent f869ce87b1
commit fefb6cdb94
27 changed files with 970 additions and 667 deletions
@@ -1121,7 +1121,7 @@ type AggregateChartConfiguration {
aggregateOperation: AggregateOperations!
label: String
displayDataLabel: Boolean
format: String
numberFormat: ChartNumberFormat
description: String
filter: JSON
timezone: String
@@ -1156,6 +1156,12 @@ enum WidgetConfigurationType {
EMAIL_THREAD
}
"""Format used to display the chart value"""
enum ChartNumberFormat {
SHORT
FULL
}
type StandaloneRichTextConfiguration {
configurationType: WidgetConfigurationType!
body: RichTextBody!
@@ -809,7 +809,7 @@ export interface AggregateChartConfiguration {
aggregateOperation: AggregateOperations
label?: Scalars['String']
displayDataLabel?: Scalars['Boolean']
format?: Scalars['String']
numberFormat?: ChartNumberFormat
description?: Scalars['String']
filter?: Scalars['JSON']
timezone?: Scalars['String']
@@ -822,6 +822,10 @@ export interface AggregateChartConfiguration {
export type WidgetConfigurationType = 'AGGREGATE_CHART' | 'PIE_CHART' | 'BAR_CHART' | 'LINE_CHART' | 'IFRAME' | 'STANDALONE_RICH_TEXT' | 'VIEW' | 'FIELD' | 'FIELDS' | 'TIMELINE' | 'TASKS' | 'NOTES' | 'FILES' | 'EMAILS' | 'CALENDAR' | 'FIELD_RICH_TEXT' | 'WORKFLOW' | 'WORKFLOW_VERSION' | 'WORKFLOW_RUN' | 'FRONT_COMPONENT' | 'RECORD_TABLE' | 'EMAIL_THREAD'
/** Format used to display the chart value */
export type ChartNumberFormat = 'SHORT' | 'FULL'
export interface StandaloneRichTextConfiguration {
configurationType: WidgetConfigurationType
body: RichTextBody
@@ -3817,7 +3821,7 @@ export interface AggregateChartConfigurationGenqlSelection{
aggregateOperation?: boolean | number
label?: boolean | number
displayDataLabel?: boolean | number
format?: boolean | number
numberFormat?: boolean | number
description?: boolean | number
filter?: boolean | number
timezone?: boolean | number
@@ -8824,6 +8828,11 @@ export const enumWidgetConfigurationType = {
EMAIL_THREAD: 'EMAIL_THREAD' as const
}
export const enumChartNumberFormat = {
SHORT: 'SHORT' as const,
FULL: 'FULL' as const
}
export const enumObjectRecordGroupByDateGranularity = {
DAY: 'DAY' as const,
MONTH: 'MONTH' as const,
File diff suppressed because it is too large Load Diff