[BREAKING_CHANGE_DASHBOARDS][DASHBOARD_CACHE_FLUSH_REQUIRED] Refactor page layout widget configuration type (#16671)

# Introduction
In this pull-request we're refactoring the page layout widget
configuration entity to be containing its discriminated key simplifying
underlying code and maintainability
- Made the configuration and title non nullable
- Introduced a generic predicate for the `widgetConfigurationType`
- Upgraded command to remove `graphType` and insert new
`configurationType` to existing entries
- Migrated frontend to new type system

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
This commit is contained in:
Paul Rastoin
2025-12-29 15:46:59 +01:00
committed by GitHub
parent 2b9728230a
commit 4135a6473a
221 changed files with 3241 additions and 1947 deletions
@@ -149,12 +149,12 @@ export type AggregateChartConfiguration = {
__typename?: 'AggregateChartConfiguration';
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
prefix?: Maybe<Scalars['String']>;
ratioAggregateConfig?: Maybe<RatioAggregateConfig>;
@@ -351,14 +351,15 @@ export type BarChartConfiguration = {
aggregateOperation: AggregateOperations;
axisNameDisplay?: Maybe<AxisNameDisplay>;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
displayLegend?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
groupMode?: Maybe<BarChartGroupMode>;
isCumulative?: Maybe<Scalars['Boolean']>;
layout: BarChartLayout;
omitNullValues?: Maybe<Scalars['Boolean']>;
primaryAxisDateGranularity?: Maybe<ObjectRecordGroupByDateGranularity>;
primaryAxisGroupByFieldMetadataId: Scalars['UUID'];
@@ -379,6 +380,12 @@ export enum BarChartGroupMode {
STACKED = 'STACKED'
}
/** Layout orientation for bar charts */
export enum BarChartLayout {
HORIZONTAL = 'HORIZONTAL',
VERTICAL = 'VERTICAL'
}
export type Billing = {
__typename?: 'Billing';
billingUrl?: Maybe<Scalars['String']>;
@@ -899,12 +906,12 @@ export type CreatePageLayoutTabInput = {
};
export type CreatePageLayoutWidgetInput = {
configuration?: InputMaybe<Scalars['JSON']>;
configuration: Scalars['JSON'];
gridPosition: GridPositionInput;
objectMetadataId?: InputMaybe<Scalars['UUID']>;
pageLayoutTabId: Scalars['UUID'];
title: Scalars['String'];
type?: InputMaybe<WidgetType>;
type: WidgetType;
};
export type CreateRemoteServerInput = {
@@ -1476,11 +1483,11 @@ export type GaugeChartConfiguration = {
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
timezone?: Maybe<Scalars['String']>;
};
@@ -1519,16 +1526,6 @@ export enum GraphOrderBy {
VALUE_DESC = 'VALUE_DESC'
}
/** Type of graph widget */
export enum GraphType {
AGGREGATE = 'AGGREGATE',
GAUGE = 'GAUGE',
HORIZONTAL_BAR = 'HORIZONTAL_BAR',
LINE = 'LINE',
PIE = 'PIE',
VERTICAL_BAR = 'VERTICAL_BAR'
}
export type GridPosition = {
__typename?: 'GridPosition';
column: Scalars['Float'];
@@ -1567,6 +1564,7 @@ export enum IdentityProviderType {
export type IframeConfiguration = {
__typename?: 'IframeConfiguration';
configurationType: WidgetConfigurationType;
url?: Maybe<Scalars['String']>;
};
@@ -1720,12 +1718,12 @@ export type LineChartConfiguration = {
aggregateOperation: AggregateOperations;
axisNameDisplay?: Maybe<AxisNameDisplay>;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
displayLegend?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
isCumulative?: Maybe<Scalars['Boolean']>;
isStacked?: Maybe<Scalars['Boolean']>;
omitNullValues?: Maybe<Scalars['Boolean']>;
@@ -3126,7 +3124,7 @@ export enum PageLayoutType {
export type PageLayoutWidget = {
__typename?: 'PageLayoutWidget';
configuration?: Maybe<WidgetConfiguration>;
configuration: WidgetConfiguration;
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
gridPosition: GridPosition;
@@ -3177,13 +3175,13 @@ export type PieChartConfiguration = {
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
dateGranularity?: Maybe<ObjectRecordGroupByDateGranularity>;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
displayLegend?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
groupByFieldMetadataId: Scalars['UUID'];
groupBySubFieldName?: Maybe<Scalars['String']>;
hideEmptyCategory?: Maybe<Scalars['Boolean']>;
@@ -3729,11 +3727,6 @@ export type RatioAggregateConfig = {
optionValue: Scalars['String'];
};
export type RatioAggregateConfigInput = {
fieldMetadataId: Scalars['UUID'];
optionValue: Scalars['String'];
};
export type Relation = {
__typename?: 'Relation';
sourceFieldMetadata: Field;
@@ -4039,6 +4032,7 @@ export type SignedFile = {
export type StandaloneRichTextConfiguration = {
__typename?: 'StandaloneRichTextConfiguration';
body: RichTextV2Body;
configurationType: WidgetConfigurationType;
};
export type StandardOverrides = {
@@ -4797,6 +4791,29 @@ export type Webhook = {
export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | PieChartConfiguration | StandaloneRichTextConfiguration;
export enum WidgetConfigurationType {
AGGREGATE_CHART = 'AGGREGATE_CHART',
BAR_CHART = 'BAR_CHART',
CALENDAR = 'CALENDAR',
EMAILS = 'EMAILS',
FIELD = 'FIELD',
FIELDS = 'FIELDS',
FIELD_RICH_TEXT = 'FIELD_RICH_TEXT',
FILES = 'FILES',
GAUGE_CHART = 'GAUGE_CHART',
IFRAME = 'IFRAME',
LINE_CHART = 'LINE_CHART',
NOTES = 'NOTES',
PIE_CHART = 'PIE_CHART',
STANDALONE_RICH_TEXT = 'STANDALONE_RICH_TEXT',
TASKS = 'TASKS',
TIMELINE = 'TIMELINE',
VIEW = 'VIEW',
WORKFLOW = 'WORKFLOW',
WORKFLOW_RUN = 'WORKFLOW_RUN',
WORKFLOW_VERSION = 'WORKFLOW_VERSION'
}
export enum WidgetType {
CALENDAR = 'CALENDAR',
EMAILS = 'EMAILS',
+50 -30
View File
@@ -149,12 +149,12 @@ export type AggregateChartConfiguration = {
__typename?: 'AggregateChartConfiguration';
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
prefix?: Maybe<Scalars['String']>;
ratioAggregateConfig?: Maybe<RatioAggregateConfig>;
@@ -351,14 +351,15 @@ export type BarChartConfiguration = {
aggregateOperation: AggregateOperations;
axisNameDisplay?: Maybe<AxisNameDisplay>;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
displayLegend?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
groupMode?: Maybe<BarChartGroupMode>;
isCumulative?: Maybe<Scalars['Boolean']>;
layout: BarChartLayout;
omitNullValues?: Maybe<Scalars['Boolean']>;
primaryAxisDateGranularity?: Maybe<ObjectRecordGroupByDateGranularity>;
primaryAxisGroupByFieldMetadataId: Scalars['UUID'];
@@ -379,6 +380,12 @@ export enum BarChartGroupMode {
STACKED = 'STACKED'
}
/** Layout orientation for bar charts */
export enum BarChartLayout {
HORIZONTAL = 'HORIZONTAL',
VERTICAL = 'VERTICAL'
}
export type Billing = {
__typename?: 'Billing';
billingUrl?: Maybe<Scalars['String']>;
@@ -890,12 +897,12 @@ export type CreatePageLayoutTabInput = {
};
export type CreatePageLayoutWidgetInput = {
configuration?: InputMaybe<Scalars['JSON']>;
configuration: Scalars['JSON'];
gridPosition: GridPositionInput;
objectMetadataId?: InputMaybe<Scalars['UUID']>;
pageLayoutTabId: Scalars['UUID'];
title: Scalars['String'];
type?: InputMaybe<WidgetType>;
type: WidgetType;
};
export type CreateRoleInput = {
@@ -1452,11 +1459,11 @@ export type GaugeChartConfiguration = {
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
timezone?: Maybe<Scalars['String']>;
};
@@ -1495,16 +1502,6 @@ export enum GraphOrderBy {
VALUE_DESC = 'VALUE_DESC'
}
/** Type of graph widget */
export enum GraphType {
AGGREGATE = 'AGGREGATE',
GAUGE = 'GAUGE',
HORIZONTAL_BAR = 'HORIZONTAL_BAR',
LINE = 'LINE',
PIE = 'PIE',
VERTICAL_BAR = 'VERTICAL_BAR'
}
export type GridPosition = {
__typename?: 'GridPosition';
column: Scalars['Float'];
@@ -1543,6 +1540,7 @@ export enum IdentityProviderType {
export type IframeConfiguration = {
__typename?: 'IframeConfiguration';
configurationType: WidgetConfigurationType;
url?: Maybe<Scalars['String']>;
};
@@ -1696,12 +1694,12 @@ export type LineChartConfiguration = {
aggregateOperation: AggregateOperations;
axisNameDisplay?: Maybe<AxisNameDisplay>;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
displayLegend?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
isCumulative?: Maybe<Scalars['Boolean']>;
isStacked?: Maybe<Scalars['Boolean']>;
omitNullValues?: Maybe<Scalars['Boolean']>;
@@ -3047,7 +3045,7 @@ export enum PageLayoutType {
export type PageLayoutWidget = {
__typename?: 'PageLayoutWidget';
configuration?: Maybe<WidgetConfiguration>;
configuration: WidgetConfiguration;
createdAt: Scalars['DateTime'];
deletedAt?: Maybe<Scalars['DateTime']>;
gridPosition: GridPosition;
@@ -3098,13 +3096,13 @@ export type PieChartConfiguration = {
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
color?: Maybe<Scalars['String']>;
configurationType: WidgetConfigurationType;
dateGranularity?: Maybe<ObjectRecordGroupByDateGranularity>;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
displayLegend?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
graphType: GraphType;
groupByFieldMetadataId: Scalars['UUID'];
groupBySubFieldName?: Maybe<Scalars['String']>;
hideEmptyCategory?: Maybe<Scalars['Boolean']>;
@@ -3580,11 +3578,6 @@ export type RatioAggregateConfig = {
optionValue: Scalars['String'];
};
export type RatioAggregateConfigInput = {
fieldMetadataId: Scalars['UUID'];
optionValue: Scalars['String'];
};
export type Relation = {
__typename?: 'Relation';
sourceFieldMetadata: Field;
@@ -3876,6 +3869,7 @@ export type SignedFile = {
export type StandaloneRichTextConfiguration = {
__typename?: 'StandaloneRichTextConfiguration';
body: RichTextV2Body;
configurationType: WidgetConfigurationType;
};
export type StandardOverrides = {
@@ -4616,6 +4610,29 @@ export type Webhook = {
export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | PieChartConfiguration | StandaloneRichTextConfiguration;
export enum WidgetConfigurationType {
AGGREGATE_CHART = 'AGGREGATE_CHART',
BAR_CHART = 'BAR_CHART',
CALENDAR = 'CALENDAR',
EMAILS = 'EMAILS',
FIELD = 'FIELD',
FIELDS = 'FIELDS',
FIELD_RICH_TEXT = 'FIELD_RICH_TEXT',
FILES = 'FILES',
GAUGE_CHART = 'GAUGE_CHART',
IFRAME = 'IFRAME',
LINE_CHART = 'LINE_CHART',
NOTES = 'NOTES',
PIE_CHART = 'PIE_CHART',
STANDALONE_RICH_TEXT = 'STANDALONE_RICH_TEXT',
TASKS = 'TASKS',
TIMELINE = 'TIMELINE',
VIEW = 'VIEW',
WORKFLOW = 'WORKFLOW',
WORKFLOW_RUN = 'WORKFLOW_RUN',
WORKFLOW_VERSION = 'WORKFLOW_VERSION'
}
export enum WidgetType {
CALENDAR = 'CALENDAR',
EMAILS = 'EMAILS',
@@ -4887,7 +4904,7 @@ export type SearchQueryVariables = Exact<{
export type SearchQuery = { __typename?: 'Query', search: { __typename?: 'SearchResultConnection', edges: Array<{ __typename?: 'SearchResultEdge', cursor: string, node: { __typename?: 'SearchRecord', recordId: any, objectNameSingular: string, label: string, imageUrl?: string | null, tsRankCD: number, tsRank: number } }>, pageInfo: { __typename?: 'SearchResultPageInfo', hasNextPage: boolean, endCursor?: string | null } } };
export type PageLayoutWidgetFragmentFragment = { __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration?: { __typename?: 'AggregateChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', url?: string | null } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | null };
export type PageLayoutWidgetFragmentFragment = { __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } };
export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{
id: Scalars['String'];
@@ -4895,7 +4912,7 @@ export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{
}>;
export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: any, name: string, type: PageLayoutType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: any, title: string, position: number, pageLayoutId: any, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration?: { __typename?: 'AggregateChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', url?: string | null } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | null }> | null }> | null } };
export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: any, name: string, type: PageLayoutType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: any, title: string, position: number, pageLayoutId: any, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: any, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } }> | null }> | null } };
export type OnDbEventSubscriptionVariables = Exact<{
input: OnDbEventInput;
@@ -5214,7 +5231,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
}
configuration {
... on BarChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
primaryAxisGroupByFieldMetadataId
@@ -5235,12 +5252,13 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
description
filter
groupMode
layout
isCumulative
timezone
firstDayOfTheWeek
}
... on LineChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
primaryAxisGroupByFieldMetadataId
@@ -5266,7 +5284,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
firstDayOfTheWeek
}
... on PieChartConfiguration {
graphType
configurationType
groupByFieldMetadataId
aggregateFieldMetadataId
aggregateOperation
@@ -5283,7 +5301,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
firstDayOfTheWeek
}
... on AggregateChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
label
@@ -5301,7 +5319,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
}
}
... on GaugeChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
displayDataLabel
@@ -5312,9 +5330,11 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
firstDayOfTheWeek
}
... on IframeConfiguration {
configurationType
url
}
... on StandaloneRichTextConfiguration {
configurationType
body {
blocknote
markdown
@@ -1,5 +1,6 @@
import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation';
import { isChartWidget } from '@/command-menu/pages/page-layout/utils/isChartWidget';
import { getCurrentGraphTypeFromConfig } from '@/command-menu/pages/page-layout/utils/getCurrentGraphTypeFromConfig';
import { isWidgetConfigurationOfTypeGraph } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfTypeGraph';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
@@ -116,11 +117,13 @@ export const usePageLayoutHeaderInfo = ({
return null;
}
if (!isChartWidget(widgetInEditMode)) {
if (!isWidgetConfigurationOfTypeGraph(widgetInEditMode.configuration)) {
return null;
}
const currentGraphType = widgetInEditMode.configuration.graphType;
const currentGraphType = getCurrentGraphTypeFromConfig(
widgetInEditMode.configuration,
);
const graphTypeInfo = GRAPH_TYPE_INFORMATION[currentGraphType];
const graphTypeLabel = t(graphTypeInfo.label);
@@ -1,11 +1,10 @@
import { getChartLimitMessage } from '@/command-menu/pages/page-layout/utils/getChartLimitMessage';
import { t } from '@lingui/core/macro';
import { SidePanelInformationBanner } from 'twenty-ui/display';
import { type GraphType } from '~/generated/graphql';
import { type WidgetConfigurationType } from '~/generated/graphql';
type ChartLimitInfoBannerProps = {
graphType: GraphType;
widgetConfigurationType: WidgetConfigurationType;
isPrimaryAxisDate: boolean;
primaryAxisDateGranularity: Parameters<
typeof getChartLimitMessage
@@ -13,14 +12,14 @@ type ChartLimitInfoBannerProps = {
};
export const ChartLimitInfoBanner = ({
graphType,
widgetConfigurationType,
isPrimaryAxisDate,
primaryAxisDateGranularity,
}: ChartLimitInfoBannerProps) => {
return (
<SidePanelInformationBanner
message={getChartLimitMessage({
graphType,
widgetConfigurationType,
isPrimaryAxisDate,
primaryAxisDateGranularity,
})}
@@ -19,11 +19,11 @@ import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { isFieldMetadataDateKind } from 'twenty-shared/utils';
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { assertChartWidgetOrThrow } from '@/command-menu/pages/page-layout/utils/assertChartWidgetOrThrow';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { getCurrentGraphTypeFromConfig } from '@/command-menu/pages/page-layout/utils/getCurrentGraphTypeFromConfig';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { GraphType } from '~/generated/graphql';
const StyledCommandMenuContainer = styled.div`
display: flex;
@@ -42,7 +42,6 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
assertChartWidgetOrThrow(widget);
const configuration = widget.configuration;
const currentGraphType = configuration?.graphType;
const { getChartSettingsValues } = useChartSettingsValues({
objectMetadataId: widget.objectMetadataId,
@@ -81,6 +80,8 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
}
};
const currentGraphType = getCurrentGraphTypeFromConfig(configuration);
const chartSettings = GRAPH_TYPE_INFORMATION[currentGraphType].settings;
const objectMetadataItem = objectMetadataItems.find(
@@ -103,11 +104,18 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
.map((item) => item.id),
);
const primaryAxisFieldMetadataId = isBarOrLineChartConfiguration(
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
const isPieChart = isWidgetConfigurationOfType(
configuration,
)
'PieChartConfiguration',
);
const primaryAxisFieldMetadataId = isBarOrLineChart
? configuration.primaryAxisGroupByFieldMetadataId
: isPieChartConfiguration(configuration)
: isPieChart
? configuration.groupByFieldMetadataId
: null;
@@ -117,11 +125,9 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
const isPrimaryAxisDate = isFieldMetadataDateKind(primaryAxisField?.type);
const primaryAxisDateGranularity = isBarOrLineChartConfiguration(
configuration,
)
const primaryAxisDateGranularity = isBarOrLineChart
? configuration.primaryAxisDateGranularity
: isPieChartConfiguration(configuration)
: isPieChart
? configuration.dateGranularity
: null;
@@ -156,7 +162,7 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
<CommandGroup key={group.heading.id} heading={t(group.heading)}>
{shouldShowBanner && hasWidgetTooManyGroups && (
<ChartLimitInfoBanner
graphType={currentGraphType}
widgetConfigurationType={configuration.configurationType}
isPrimaryAxisDate={isPrimaryAxisDate}
primaryAxisDateGranularity={primaryAxisDateGranularity}
/>
@@ -1,8 +1,9 @@
import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { FeatureFlagKey, GraphType } from '~/generated-metadata/graphql';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { t } from '@lingui/core/macro';
import { MenuPicker } from 'twenty-ui/navigation';
@@ -1,6 +1,7 @@
import { ChartSettings } from '@/command-menu/pages/page-layout/components/ChartSettings';
import { WidgetSettingsFooter } from '@/command-menu/pages/page-layout/components/WidgetSettingsFooter';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { isChartWidget } from '@/command-menu/pages/page-layout/utils/isChartWidget';
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext';
@@ -31,11 +32,7 @@ export const CommandMenuPageLayoutChartSettings = () => {
.flatMap((tab) => tab.widgets)
.find((widget) => widget.id === pageLayoutEditingWidgetId);
if (
!isDefined(widgetInEditMode) ||
!isDefined(widgetInEditMode.configuration) ||
!('graphType' in widgetInEditMode.configuration)
) {
if (!isDefined(widgetInEditMode) || !isChartWidget(widgetInEditMode)) {
return null;
}
@@ -7,6 +7,7 @@ import { t } from '@lingui/core/macro';
import { isNonEmptyString, isString } from '@sniptt/guards';
import { useState } from 'react';
import { isDefined, isValidUrl } from 'twenty-shared/utils';
import { WidgetConfigurationType } from '~/generated/graphql';
const StyledContainer = styled.div`
display: flex;
@@ -67,6 +68,7 @@ export const CommandMenuPageLayoutIframeSettings = () => {
updatePageLayoutWidget(widgetInEditMode.id, {
configuration: {
__typename: 'IframeConfiguration',
configurationType: WidgetConfigurationType.IFRAME,
url: isNonEmptyString(trimmedValue) ? trimmedValue : null,
},
});
@@ -19,7 +19,6 @@ import {
IconChartPie,
IconFrame,
} from 'twenty-ui/display';
import { GraphType } from '~/generated-metadata/graphql';
export const CommandMenuPageLayoutWidgetTypeSelect = () => {
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
@@ -49,7 +48,6 @@ export const CommandMenuPageLayoutWidgetTypeSelect = () => {
if (!isDefined(pageLayoutEditingWidgetId)) {
const fieldSelection = buildBarChartFieldSelection();
const newWidget = createPageLayoutGraphWidget({
graphType: GraphType.VERTICAL_BAR,
fieldSelection,
});
@@ -1,7 +1,7 @@
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-record/utils/convertExtendedAggregateOperationToAggregateOperation';
import { DASHBOARD_AGGREGATE_OPERATION_RATIO } from '@/page-layout/widgets/graph/constants/DashboardAggregateOperationRatio';
@@ -53,7 +53,7 @@ export const ChartAggregateOperationSelectableListItem = ({
configuration.aggregateOperation;
const isCurrentlyRatio =
isAggregateChartConfiguration(configuration) &&
isWidgetConfigurationOfType(configuration, 'AggregateChartConfiguration') &&
isDefined(configuration.ratioAggregateConfig);
if (!isExtendedAggregateOperation(operation)) {
@@ -3,9 +3,7 @@ import { ChartRatioAggregateOperationSelectableListItem } from '@/command-menu/p
import { ChartRatioOptionValueSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartRatioOptionValueSelectionDropdownContent';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations';
import { getAvailableAggregateOperationsForFieldMetadataType } from '@/object-record/record-table/record-table-footer/utils/getAvailableAggregateOperationsForFieldMetadataType';
@@ -42,13 +40,19 @@ export const ChartAggregateOperationSelectionDropdownContent = ({
const configuration = widgetInEditMode?.configuration;
const isAggregateChart = isAggregateChartConfiguration(configuration);
const isAggregateChart = isWidgetConfigurationOfType(
configuration,
'AggregateChartConfiguration',
);
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
const isPieChart = isWidgetConfigurationOfType(
configuration,
'PieChartConfiguration',
);
if (
!isBarOrLineChartConfiguration(configuration) &&
!isAggregateChart &&
!isPieChartConfiguration(configuration)
) {
if (!isBarOrLineChart && !isAggregateChart && !isPieChart) {
throw new Error('Invalid configuration type');
}
@@ -2,7 +2,7 @@ import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pa
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout/utils/getChartAxisNameDisplayOptions';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -18,11 +18,17 @@ export const ChartAxisNameSelectionDropdownContent = () => {
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
if (!isBarOrLineChartConfiguration(widgetInEditMode?.configuration)) {
const configuration = widgetInEditMode?.configuration;
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
if (!isBarOrLineChart) {
throw new Error('Invalid configuration type');
}
const currentAxisNameDisplay = widgetInEditMode.configuration.axisNameDisplay;
const currentAxisNameDisplay = configuration.axisNameDisplay;
const dropdownId = useAvailableComponentInstanceIdOrThrow(
DropdownComponentInstanceContext,
@@ -4,10 +4,7 @@ import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pa
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isGaugeChartConfiguration } from '@/command-menu/pages/page-layout/utils/isGaugeChartConfiguration';
import { isIframeConfiguration } from '@/command-menu/pages/page-layout/utils/isIframeConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
@@ -52,17 +49,30 @@ export const ChartColorSelectionDropdownContent = () => {
return null;
}
if (isIframeConfiguration(widgetInEditMode.configuration)) {
if (
isWidgetConfigurationOfType(
widgetInEditMode.configuration,
'IframeConfiguration',
)
) {
throw new Error('Invalid configuration type');
}
const configuration = widgetInEditMode.configuration as ChartConfiguration;
if (
!isBarOrLineChartConfiguration(configuration) &&
!isGaugeChartConfiguration(configuration) &&
!isPieChartConfiguration(configuration)
) {
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
const isGaugeChart = isWidgetConfigurationOfType(
configuration,
'GaugeChartConfiguration',
);
const isPieChart = isWidgetConfigurationOfType(
configuration,
'PieChartConfiguration',
);
if (!isBarOrLineChart && !isGaugeChart && !isPieChart) {
return null;
}
@@ -3,9 +3,9 @@ import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/h
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { getDateGranularityLabel } from '@/command-menu/pages/page-layout/utils/getDateGranularityLabel';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isChartConfiguration } from '@/command-menu/pages/page-layout/utils/isChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -17,6 +17,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { type WidgetConfiguration } from '~/generated/graphql';
type ChartDateGranularitySelectionDropdownContentProps = {
axis?: 'primary' | 'secondary';
@@ -31,11 +32,15 @@ const getCurrentDateGranularity = ({
}) => {
const defaultGranularity = ObjectRecordGroupByDateGranularity.DAY;
if (isPieChartConfiguration(configuration)) {
if (isWidgetConfigurationOfType(configuration, 'PieChartConfiguration')) {
return configuration.dateGranularity || defaultGranularity;
}
if (!isBarOrLineChartConfiguration(configuration)) {
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
if (!isBarOrLineChart) {
return defaultGranularity;
}
@@ -48,6 +53,23 @@ const getCurrentDateGranularity = ({
);
};
const isChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldsConfiguration
| FieldConfiguration
| null
| undefined,
): configuration is ChartConfiguration => {
return (
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'PieChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'AggregateChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'GaugeChartConfiguration')
);
};
export const ChartDateGranularitySelectionDropdownContent = ({
axis,
}: ChartDateGranularitySelectionDropdownContentProps) => {
@@ -60,11 +82,19 @@ export const ChartDateGranularitySelectionDropdownContent = ({
throw new Error('Invalid configuration type');
}
if (!isDefined(axis) && !isPieChartConfiguration(configuration)) {
const isPieChart = isWidgetConfigurationOfType(
configuration,
'PieChartConfiguration',
);
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
if (!isDefined(axis) && !isPieChart) {
throw new Error('Invalid configuration type');
}
if (isDefined(axis) && !isBarOrLineChartConfiguration(configuration)) {
if (isDefined(axis) && !isBarOrLineChart) {
throw new Error('Invalid configuration type');
}
@@ -1,9 +1,7 @@
import { ChartAggregateOperationSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartAggregateOperationSelectionDropdownContent';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@@ -31,11 +29,19 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => {
const configuration = widgetInEditMode?.configuration;
if (
!isBarOrLineChartConfiguration(configuration) &&
!isAggregateChartConfiguration(configuration) &&
!isPieChartConfiguration(configuration)
) {
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
const isAggregateChart = isWidgetConfigurationOfType(
configuration,
'AggregateChartConfiguration',
);
const isPieChart = isWidgetConfigurationOfType(
configuration,
'PieChartConfiguration',
);
if (!isBarOrLineChart && !isAggregateChart && !isPieChart) {
throw new Error('Invalid configuration type');
}
@@ -1,13 +1,11 @@
import { ChartGroupByFieldSelectionDropdownContentBase } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContentBase';
import {
type BarChartConfiguration,
type LineChartConfiguration,
} from '~/generated/graphql';
import { type TypedBarChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedBarChartConfiguration';
import { type TypedLineChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedLineChartConfiguration';
export const ChartGroupByFieldSelectionDropdownContent = () => {
return (
<ChartGroupByFieldSelectionDropdownContentBase<
BarChartConfiguration | LineChartConfiguration
TypedBarChartConfiguration | TypedLineChartConfiguration
>
fieldMetadataIdKey="secondaryAxisGroupByFieldMetadataId"
subFieldNameKey="secondaryAxisGroupBySubFieldName"
@@ -1,9 +1,9 @@
import { ChartGroupByFieldSelectionDropdownContentBase } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContentBase';
import { type PieChartConfiguration } from '~/generated/graphql';
import { type TypedPieChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedPieChartConfiguration';
export const ChartPieFieldSelectionDropdownContent = () => {
return (
<ChartGroupByFieldSelectionDropdownContentBase<PieChartConfiguration>
<ChartGroupByFieldSelectionDropdownContentBase<TypedPieChartConfiguration>
fieldMetadataIdKey="groupByFieldMetadataId"
subFieldNameKey="groupBySubFieldName"
/>
@@ -1,6 +1,6 @@
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { DASHBOARD_AGGREGATE_OPERATION_RATIO } from '@/page-layout/widgets/graph/constants/DashboardAggregateOperationRatio';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
@@ -30,8 +30,10 @@ export const ChartRatioAggregateOperationSelectableListItem = ({
);
const isCurrentlyRatio =
isAggregateChartConfiguration(widgetInEditMode?.configuration) &&
isDefined(widgetInEditMode.configuration.ratioAggregateConfig);
isWidgetConfigurationOfType(
widgetInEditMode?.configuration,
'AggregateChartConfiguration',
) && isDefined(widgetInEditMode.configuration.ratioAggregateConfig);
const isFocused = selectedItemId === DASHBOARD_AGGREGATE_OPERATION_RATIO;
@@ -1,7 +1,7 @@
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
@@ -36,8 +36,9 @@ export const ChartRatioOptionBooleanSelectableListItem = ({
dropdownId,
);
const currentRatioConfig = isAggregateChartConfiguration(
const currentRatioConfig = isWidgetConfigurationOfType(
widgetInEditMode?.configuration,
'AggregateChartConfiguration',
)
? widgetInEditMode.configuration.ratioAggregateConfig
: undefined;
@@ -1,7 +1,7 @@
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
@@ -38,8 +38,9 @@ export const ChartRatioOptionSelectSelectableListItem = ({
dropdownId,
);
const currentRatioConfig = isAggregateChartConfiguration(
const currentRatioConfig = isWidgetConfigurationOfType(
widgetInEditMode?.configuration,
'AggregateChartConfiguration',
)
? widgetInEditMode.configuration.ratioAggregateConfig
: undefined;
@@ -2,7 +2,7 @@ import { ChartRatioOptionBooleanSelectableListItem } from '@/command-menu/pages/
import { ChartRatioOptionSelectSelectableListItem } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartRatioOptionSelectSelectableListItem';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
@@ -42,7 +42,12 @@ export const ChartRatioOptionValueSelectionDropdownContent = ({
DropdownComponentInstanceContext,
);
if (!isAggregateChartConfiguration(widgetInEditMode?.configuration)) {
if (
!isWidgetConfigurationOfType(
widgetInEditMode?.configuration,
'AggregateChartConfiguration',
)
) {
return null;
}
@@ -3,7 +3,7 @@ import { useGraphGroupBySortOptionLabels } from '@/command-menu/pages/page-layou
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -23,7 +23,9 @@ export const ChartSortByGroupByFieldDropdownContent = () => {
const configuration = widgetInEditMode?.configuration;
const isBarOrLineChart = isBarOrLineChartConfiguration(configuration);
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
if (!isBarOrLineChart) {
throw new Error('Invalid configuration type');
@@ -3,9 +3,7 @@ import { useGraphXSortOptionLabels } from '@/command-menu/pages/page-layout/hook
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { isBarChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarChartConfiguration';
import { isLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { isRelationNestedFieldDateKind } from '@/page-layout/widgets/graph/utils/isRelationNestedFieldDateKind';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@@ -30,9 +28,18 @@ export const ChartSortBySelectionDropdownContent = () => {
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
const configuration = widgetInEditMode?.configuration;
const isPieChart = isPieChartConfiguration(configuration);
const isLineChart = isLineChartConfiguration(configuration);
const isBarChart = isBarChartConfiguration(configuration);
const isPieChart = isWidgetConfigurationOfType(
configuration,
'PieChartConfiguration',
);
const isLineChart = isWidgetConfigurationOfType(
configuration,
'LineChartConfiguration',
);
const isBarChart = isWidgetConfigurationOfType(
configuration,
'BarChartConfiguration',
);
if (!isBarChart && !isLineChart && !isPieChart) {
throw new Error('Invalid configuration type');
@@ -1,13 +1,11 @@
import { ChartGroupByFieldSelectionDropdownContentBase } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContentBase';
import {
type BarChartConfiguration,
type LineChartConfiguration,
} from '~/generated/graphql';
import { type TypedBarChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedBarChartConfiguration';
import { type TypedLineChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedLineChartConfiguration';
export const ChartXAxisFieldSelectionDropdownContent = () => {
return (
<ChartGroupByFieldSelectionDropdownContentBase<
BarChartConfiguration | LineChartConfiguration
TypedBarChartConfiguration | TypedLineChartConfiguration
>
fieldMetadataIdKey="primaryAxisGroupByFieldMetadataId"
subFieldNameKey="primaryAxisGroupBySubFieldName"
@@ -0,0 +1,11 @@
import { WidgetConfigurationType } from '~/generated/graphql';
export const GRAPH_CONFIGURATION_TYPE_TO_CONFIG_TYPENAME: Partial<
Record<WidgetConfigurationType, string>
> = {
[WidgetConfigurationType.BAR_CHART]: 'BarChartConfiguration',
[WidgetConfigurationType.LINE_CHART]: 'LineChartConfiguration',
[WidgetConfigurationType.PIE_CHART]: 'PieChartConfiguration',
[WidgetConfigurationType.AGGREGATE_CHART]: 'AggregateChartConfiguration',
[WidgetConfigurationType.GAUGE_CHART]: 'GaugeChartConfiguration',
} as const;
@@ -3,6 +3,7 @@ import { GAUGE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants
import { LINE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/LineChartSettings';
import { PIE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/PieChartSettings';
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { getBarChartSettings } from '@/command-menu/pages/page-layout/utils/getBarChartSettings';
import { type MessageDescriptor } from '@lingui/core';
import { msg } from '@lingui/core/macro';
@@ -15,7 +16,7 @@ import {
IconGauge,
IconSum,
} from 'twenty-ui/display';
import { GraphType } from '~/generated-metadata/graphql';
import { BarChartLayout } from '~/generated/graphql';
export const GRAPH_TYPE_INFORMATION: Record<
GraphType,
@@ -28,12 +29,12 @@ export const GRAPH_TYPE_INFORMATION: Record<
[GraphType.VERTICAL_BAR]: {
label: msg`Vertical Bar Chart`,
icon: IconChartBar,
settings: getBarChartSettings(GraphType.VERTICAL_BAR),
settings: getBarChartSettings(BarChartLayout.VERTICAL),
},
[GraphType.HORIZONTAL_BAR]: {
label: msg`Horizontal Bar Chart`,
icon: IconChartBarHorizontal,
settings: getBarChartSettings(GraphType.HORIZONTAL_BAR),
settings: getBarChartSettings(BarChartLayout.HORIZONTAL),
},
[GraphType.PIE]: {
label: msg`Pie Chart`,
@@ -1,10 +0,0 @@
import { GraphType } from '~/generated-metadata/graphql';
export const GRAPH_TYPE_TO_CONFIG_TYPENAME = {
[GraphType.VERTICAL_BAR]: 'BarChartConfiguration',
[GraphType.HORIZONTAL_BAR]: 'BarChartConfiguration',
[GraphType.LINE]: 'LineChartConfiguration',
[GraphType.PIE]: 'PieChartConfiguration',
[GraphType.AGGREGATE]: 'AggregateChartConfiguration',
[GraphType.GAUGE]: 'GaugeChartConfiguration',
} as const;
@@ -3,16 +3,17 @@ import { RecoilRoot } from 'recoil';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type TypedBarChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedBarChartConfiguration';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import {
AggregateOperations,
AxisNameDisplay,
type BarChartConfiguration,
BarChartGroupMode,
BarChartLayout,
FieldMetadataType,
GraphOrderBy,
GraphType,
WidgetConfigurationType,
} from '~/generated-metadata/graphql';
import { useChartSettingsValues } from '@/command-menu/pages/page-layout/hooks/useChartSettingsValues';
@@ -59,13 +60,12 @@ const mockObjectMetadataItem: ObjectMetadataItem = {
} as ObjectMetadataItem;
const buildBarChartConfiguration = (
overrides: Partial<BarChartConfiguration>,
): BarChartConfiguration =>
overrides: Partial<TypedBarChartConfiguration>,
): TypedBarChartConfiguration =>
({
__typename: 'BarChartConfiguration',
aggregateFieldMetadataId: 'field-amount',
aggregateOperation: AggregateOperations.SUM,
graphType: GraphType.VERTICAL_BAR,
primaryAxisGroupByFieldMetadataId: 'field-company-name',
primaryAxisGroupBySubFieldName: null,
secondaryAxisGroupByFieldMetadataId: null,
@@ -76,7 +76,7 @@ const buildBarChartConfiguration = (
displayDataLabel: false,
groupMode: 'GROUPED',
...overrides,
}) as BarChartConfiguration;
}) as TypedBarChartConfiguration;
const renderUseChartSettingsValues = (configuration: ChartConfiguration) => {
return renderHook(
@@ -102,7 +102,6 @@ const renderUseChartSettingsValues = (configuration: ChartConfiguration) => {
describe('useChartSettingsValues', () => {
describe('Vertical bar chart (1D - single grouping)', () => {
const verticalBarConfig = buildBarChartConfiguration({
graphType: GraphType.VERTICAL_BAR,
primaryAxisGroupByFieldMetadataId: 'field-company-name',
secondaryAxisGroupByFieldMetadataId: null,
});
@@ -172,7 +171,7 @@ describe('useChartSettingsValues', () => {
describe('Horizontal bar chart (1D - single grouping)', () => {
const horizontalBarConfig = buildBarChartConfiguration({
graphType: GraphType.HORIZONTAL_BAR,
layout: BarChartLayout.HORIZONTAL,
primaryAxisGroupByFieldMetadataId: 'field-company-name',
secondaryAxisGroupByFieldMetadataId: null,
});
@@ -213,7 +212,7 @@ describe('useChartSettingsValues', () => {
describe('Vertical bar chart (2D - with secondary grouping)', () => {
const verticalBar2DConfig = buildBarChartConfiguration({
graphType: GraphType.VERTICAL_BAR,
layout: BarChartLayout.VERTICAL,
primaryAxisGroupByFieldMetadataId: 'field-company-name',
secondaryAxisGroupByFieldMetadataId: 'field-stage',
secondaryAxisOrderBy: GraphOrderBy.FIELD_DESC,
@@ -253,7 +252,7 @@ describe('useChartSettingsValues', () => {
describe('Horizontal bar chart (2D - with secondary grouping)', () => {
const horizontalBar2DConfig = buildBarChartConfiguration({
graphType: GraphType.HORIZONTAL_BAR,
layout: BarChartLayout.HORIZONTAL,
primaryAxisGroupByFieldMetadataId: 'field-company-name',
secondaryAxisGroupByFieldMetadataId: 'field-stage',
secondaryAxisOrderBy: GraphOrderBy.FIELD_DESC,
@@ -282,7 +281,7 @@ describe('useChartSettingsValues', () => {
describe('Composite field with subfield', () => {
const configWithSubField = buildBarChartConfiguration({
graphType: GraphType.VERTICAL_BAR,
layout: BarChartLayout.VERTICAL,
primaryAxisGroupByFieldMetadataId: 'field-full-name',
primaryAxisGroupBySubFieldName: 'firstName',
});
@@ -345,7 +344,7 @@ describe('useChartSettingsValues', () => {
it('should return capitalized color when color is set', () => {
const config = buildBarChartConfiguration({
color: 'blue',
} as Partial<BarChartConfiguration>);
});
const { result } = renderUseChartSettingsValues(config);
@@ -525,7 +524,7 @@ describe('useChartSettingsValues', () => {
describe('Critical: Proves no swapping occurs', () => {
it('horizontal bar with NULL secondary should still return primary for DATA_ON_DISPLAY_X', () => {
const horizontalConfig = buildBarChartConfiguration({
graphType: GraphType.HORIZONTAL_BAR,
layout: BarChartLayout.HORIZONTAL,
primaryAxisGroupByFieldMetadataId: 'field-company-name',
secondaryAxisGroupByFieldMetadataId: null,
});
@@ -554,12 +553,14 @@ describe('useChartSettingsValues', () => {
const verticalConfig = buildBarChartConfiguration({
...baseConfig,
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
});
const horizontalConfig = buildBarChartConfiguration({
...baseConfig,
graphType: GraphType.HORIZONTAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.HORIZONTAL,
});
const { result: verticalResult } =
@@ -1,10 +1,12 @@
import { GRAPH_TYPE_TO_CONFIG_TYPENAME } from '@/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename';
import { GRAPH_CONFIGURATION_TYPE_TO_CONFIG_TYPENAME } from '@/command-menu/pages/page-layout/constants/GraphConfigurationTypeToConfigTypename';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { convertAggregateOperationForDateField } from '@/command-menu/pages/page-layout/utils/convertAggregateOperationForDateField';
import { convertBarOrLineChartConfigToPieChart } from '@/command-menu/pages/page-layout/utils/convertBarOrLineChartConfigToPieChart';
import { convertPieChartConfigToBarOrLineChart } from '@/command-menu/pages/page-layout/utils/convertPieChartConfigToBarOrLineChart';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { getConfigurationTypeFromGraphType } from '@/command-menu/pages/page-layout/utils/getConfigurationTypeFromGraphType';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { isWidgetConfigurationOfTypeGraph } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfTypeGraph';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
@@ -16,7 +18,7 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { GraphType } from '~/generated/graphql';
import { BarChartLayout } from '~/generated/graphql';
export const useGetConfigToUpdateAfterGraphTypeChange = ({
pageLayoutId,
@@ -75,13 +77,20 @@ export const useGetConfigToUpdateAfterGraphTypeChange = ({
throw new Error('Widget configuration not found in draft state');
}
const currentConfiguration =
widgetInDraft.configuration as ChartConfiguration;
const currentConfiguration = widgetInDraft.configuration;
let configToUpdate: Record<string, any> = {
__typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType],
graphType,
};
if (!isWidgetConfigurationOfTypeGraph(currentConfiguration)) {
throw new Error('Widget configuration is not a chart configuration');
}
const newConfigurationType =
getConfigurationTypeFromGraphType(graphType);
let configToUpdate = {
__typename:
GRAPH_CONFIGURATION_TYPE_TO_CONFIG_TYPENAME[newConfigurationType],
configurationType: newConfigurationType,
} as Partial<ChartConfiguration>;
if (
graphType !== GraphType.AGGREGATE &&
@@ -106,13 +115,26 @@ export const useGetConfigToUpdateAfterGraphTypeChange = ({
}
const isPieChart = graphType === GraphType.PIE;
const isVerticalBarChart = graphType === GraphType.VERTICAL_BAR;
const isHorizontalBarChart = graphType === GraphType.HORIZONTAL_BAR;
const isLineChart = graphType === GraphType.LINE;
const isBarOrLineChart =
graphType === GraphType.VERTICAL_BAR ||
graphType === GraphType.HORIZONTAL_BAR ||
graphType === GraphType.LINE;
isVerticalBarChart || isHorizontalBarChart || isLineChart;
const wasBarOrLineChart =
isBarOrLineChartConfiguration(currentConfiguration);
const wasPieChart = isPieChartConfiguration(currentConfiguration);
isWidgetConfigurationOfType(
currentConfiguration,
'BarChartConfiguration',
) ||
isWidgetConfigurationOfType(
currentConfiguration,
'LineChartConfiguration',
);
const wasPieChart = isWidgetConfigurationOfType(
currentConfiguration,
'PieChartConfiguration',
);
if (isPieChart && wasBarOrLineChart) {
configToUpdate = {
@@ -128,6 +150,20 @@ export const useGetConfigToUpdateAfterGraphTypeChange = ({
};
}
if (isHorizontalBarChart) {
configToUpdate = {
...configToUpdate,
layout: BarChartLayout.HORIZONTAL,
};
}
if (isVerticalBarChart) {
configToUpdate = {
...configToUpdate,
layout: BarChartLayout.VERTICAL,
};
}
const activeTabId = snapshot.getLoadable(activeTabIdState).getValue();
if (isDefined(activeTabId) && isDefined(currentlyEditingWidgetId)) {
@@ -135,12 +171,12 @@ export const useGetConfigToUpdateAfterGraphTypeChange = ({
.getLoadable(pageLayoutCurrentLayoutsState)
.getValue();
const updatedLayouts = updateWidgetMinimumSizeForGraphType(
graphType,
currentlyEditingWidgetId,
activeTabId,
const updatedLayouts = updateWidgetMinimumSizeForGraphType({
configurationType: newConfigurationType,
widgetId: currentlyEditingWidgetId,
tabId: activeTabId,
currentLayouts,
);
});
set(pageLayoutCurrentLayoutsState, updatedLayouts);
}
@@ -1,14 +1,12 @@
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type GaugeChartConfiguration,
type LineChartConfiguration,
type PieChartConfiguration,
} from '~/generated/graphql';
import { type TypedGaugeChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedGaugeChartConfiguration';
import { type TypedAggregateChartConfiguration } from './TypedAggregateChartConfiguration';
import { type TypedBarChartConfiguration } from './TypedBarChartConfiguration';
import { type TypedLineChartConfiguration } from './TypedLineChartConfiguration';
import { type TypedPieChartConfiguration } from './TypedPieChartConfiguration';
export type ChartConfiguration =
| BarChartConfiguration
| LineChartConfiguration
| PieChartConfiguration
| AggregateChartConfiguration
| GaugeChartConfiguration;
| TypedBarChartConfiguration
| TypedLineChartConfiguration
| TypedPieChartConfiguration
| TypedAggregateChartConfiguration
| TypedGaugeChartConfiguration;
@@ -1,4 +1,3 @@
import { type ChartFilters } from '@/command-menu/pages/page-layout/types/ChartFilters';
import { type ChartWidgetConfiguration } from '@/command-menu/pages/page-layout/types/ChartWidgetConfiguration';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { type ModifiedProperties } from 'twenty-shared/types';
@@ -8,9 +7,6 @@ export type ChartWidget = ModifiedProperties<
PageLayoutWidget,
{
type: WidgetType.GRAPH;
configuration: ModifiedProperties<
ChartWidgetConfiguration,
{ filter?: ChartFilters }
>;
configuration: ChartWidgetConfiguration;
}
>;
@@ -1,14 +1,12 @@
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type GaugeChartConfiguration,
type LineChartConfiguration,
type PieChartConfiguration,
} from '~/generated/graphql';
import { type TypedAggregateChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedAggregateChartConfiguration';
import { type TypedBarChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedBarChartConfiguration';
import { type TypedGaugeChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedGaugeChartConfiguration';
import { type TypedLineChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedLineChartConfiguration';
import { type TypedPieChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedPieChartConfiguration';
export type ChartWidgetConfiguration =
| BarChartConfiguration
| GaugeChartConfiguration
| LineChartConfiguration
| AggregateChartConfiguration
| PieChartConfiguration;
| TypedBarChartConfiguration
| TypedGaugeChartConfiguration
| TypedLineChartConfiguration
| TypedAggregateChartConfiguration
| TypedPieChartConfiguration;
@@ -0,0 +1,8 @@
export enum GraphType {
VERTICAL_BAR = 'VERTICAL_BAR',
HORIZONTAL_BAR = 'HORIZONTAL_BAR',
LINE = 'LINE',
PIE = 'PIE',
AGGREGATE = 'AGGREGATE',
GAUGE = 'GAUGE',
}
@@ -0,0 +1,8 @@
import {
type AggregateChartConfiguration,
type WidgetConfigurationType,
} from '~/generated/graphql';
export type TypedAggregateChartConfiguration = AggregateChartConfiguration & {
configurationType: WidgetConfigurationType.AGGREGATE_CHART;
};
@@ -0,0 +1,8 @@
import {
type BarChartConfiguration,
type WidgetConfigurationType,
} from '~/generated/graphql';
export type TypedBarChartConfiguration = BarChartConfiguration & {
configurationType: WidgetConfigurationType.BAR_CHART;
};
@@ -0,0 +1,8 @@
import {
type GaugeChartConfiguration,
type WidgetConfigurationType,
} from '~/generated/graphql';
export type TypedGaugeChartConfiguration = GaugeChartConfiguration & {
configurationType: WidgetConfigurationType.GAUGE_CHART;
};
@@ -0,0 +1,8 @@
import {
type LineChartConfiguration,
type WidgetConfigurationType,
} from '~/generated/graphql';
export type TypedLineChartConfiguration = LineChartConfiguration & {
configurationType: WidgetConfigurationType.LINE_CHART;
};
@@ -0,0 +1,8 @@
import {
type PieChartConfiguration,
type WidgetConfigurationType,
} from '~/generated/graphql';
export type TypedPieChartConfiguration = PieChartConfiguration & {
configurationType: WidgetConfigurationType.PIE_CHART;
};
@@ -0,0 +1,51 @@
import { assertChartWidgetOrThrow } from '@/command-menu/pages/page-layout/utils/assertChartWidgetOrThrow';
import {
ALL_CHART_CONFIGURATIONS,
createTestWidget,
TEST_BAR_CHART_CONFIGURATION,
TEST_IFRAME_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('assertChartWidgetOrThrow', () => {
it('does not throw for valid chart widget', () => {
const widget = createTestWidget({
configuration: TEST_BAR_CHART_CONFIGURATION,
});
expect(() => assertChartWidgetOrThrow(widget)).not.toThrow();
});
it('throws when objectMetadataId is missing', () => {
const widget = createTestWidget({ objectMetadataId: undefined });
expect(() => assertChartWidgetOrThrow(widget)).toThrow(
'Widget objectMetadataId is required',
);
});
it('throws when objectMetadataId is null', () => {
const widget = createTestWidget({ objectMetadataId: null });
expect(() => assertChartWidgetOrThrow(widget)).toThrow(
'Widget objectMetadataId is required',
);
});
it('throws when configuration is not a valid chart type', () => {
const widget = createTestWidget({
configuration: TEST_IFRAME_CONFIGURATION,
});
expect(() => assertChartWidgetOrThrow(widget)).toThrow(
'Expected chart configuration but got IframeConfiguration',
);
});
it('passes for all valid chart types', () => {
ALL_CHART_CONFIGURATIONS.forEach((config) => {
const widget = createTestWidget({ configuration: config });
expect(() => assertChartWidgetOrThrow(widget)).not.toThrow();
});
});
});
@@ -1,9 +1,10 @@
import { type TypedBarChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedBarChartConfiguration';
import { type TypedPieChartConfiguration } from '@/command-menu/pages/page-layout/types/TypedPieChartConfiguration';
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
import {
type BarChartConfiguration,
BarChartGroupMode,
GraphOrderBy,
type PieChartConfiguration,
WidgetConfigurationType,
} from '~/generated/graphql';
import { buildChartGroupByFieldConfigUpdate } from '@/command-menu/pages/page-layout/utils/buildChartGroupByFieldConfigUpdate';
@@ -12,7 +13,8 @@ describe('buildChartGroupByFieldConfigUpdate', () => {
const result = buildChartGroupByFieldConfigUpdate({
configuration: {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration,
configurationType: WidgetConfigurationType.BAR_CHART,
} as TypedBarChartConfiguration,
fieldMetadataIdKey: 'primaryAxisGroupByFieldMetadataId',
subFieldNameKey: 'primaryAxisGroupBySubFieldName',
fieldId: 'field',
@@ -29,7 +31,8 @@ describe('buildChartGroupByFieldConfigUpdate', () => {
const result = buildChartGroupByFieldConfigUpdate({
configuration: {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration,
configurationType: WidgetConfigurationType.BAR_CHART,
} as TypedBarChartConfiguration,
fieldMetadataIdKey: 'primaryAxisGroupByFieldMetadataId',
subFieldNameKey: 'primaryAxisGroupBySubFieldName',
fieldId: null,
@@ -46,7 +49,8 @@ describe('buildChartGroupByFieldConfigUpdate', () => {
const result = buildChartGroupByFieldConfigUpdate({
configuration: {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration,
configurationType: WidgetConfigurationType.BAR_CHART,
} as TypedBarChartConfiguration,
fieldMetadataIdKey: 'secondaryAxisGroupByFieldMetadataId',
subFieldNameKey: 'secondaryAxisGroupBySubFieldName',
fieldId: 'field',
@@ -62,7 +66,8 @@ describe('buildChartGroupByFieldConfigUpdate', () => {
const result = buildChartGroupByFieldConfigUpdate({
configuration: {
__typename: 'PieChartConfiguration',
} as PieChartConfiguration,
configurationType: WidgetConfigurationType.PIE_CHART,
} as TypedPieChartConfiguration,
fieldMetadataIdKey: 'groupByFieldMetadataId',
subFieldNameKey: 'groupBySubFieldName',
fieldId: 'field',
@@ -0,0 +1,122 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { convertAggregateOperationForDateField } from '@/command-menu/pages/page-layout/utils/convertAggregateOperationForDateField';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { FieldMetadataType } from 'twenty-shared/types';
import { TEST_BAR_CHART_CONFIGURATION } from '~/testing/mock-data/widget-configurations';
const createMockObjectMetadataItem = (
fields: { id: string; type: FieldMetadataType }[],
): ObjectMetadataItem =>
({
id: 'object-1',
fields: fields.map((f) => ({ ...f, name: 'field' })),
}) as ObjectMetadataItem;
describe('convertAggregateOperationForDateField', () => {
it('returns COUNT when date field uses MIN operation', () => {
const config: ChartConfiguration = {
...TEST_BAR_CHART_CONFIGURATION,
aggregateFieldMetadataId: 'date-field',
aggregateOperation: AggregateOperations.MIN,
};
const objectMetadataItem = createMockObjectMetadataItem([
{ id: 'date-field', type: FieldMetadataType.DATE },
]);
const result = convertAggregateOperationForDateField(
config,
objectMetadataItem,
);
expect(result).toBe(AggregateOperations.COUNT);
});
it('returns COUNT when datetime field uses MAX operation', () => {
const config: ChartConfiguration = {
...TEST_BAR_CHART_CONFIGURATION,
aggregateFieldMetadataId: 'datetime-field',
aggregateOperation: AggregateOperations.MAX,
};
const objectMetadataItem = createMockObjectMetadataItem([
{ id: 'datetime-field', type: FieldMetadataType.DATE_TIME },
]);
const result = convertAggregateOperationForDateField(
config,
objectMetadataItem,
);
expect(result).toBe(AggregateOperations.COUNT);
});
it('returns undefined when field is not a date type', () => {
const config: ChartConfiguration = {
...TEST_BAR_CHART_CONFIGURATION,
aggregateFieldMetadataId: 'number-field',
aggregateOperation: AggregateOperations.MIN,
};
const objectMetadataItem = createMockObjectMetadataItem([
{ id: 'number-field', type: FieldMetadataType.NUMBER },
]);
const result = convertAggregateOperationForDateField(
config,
objectMetadataItem,
);
expect(result).toBeUndefined();
});
it('returns undefined when operation is not MIN or MAX', () => {
const config: ChartConfiguration = {
...TEST_BAR_CHART_CONFIGURATION,
aggregateFieldMetadataId: 'date-field',
aggregateOperation: AggregateOperations.SUM,
};
const objectMetadataItem = createMockObjectMetadataItem([
{ id: 'date-field', type: FieldMetadataType.DATE },
]);
const result = convertAggregateOperationForDateField(
config,
objectMetadataItem,
);
expect(result).toBeUndefined();
});
it('returns undefined when objectMetadataItem is undefined', () => {
const config: ChartConfiguration = {
...TEST_BAR_CHART_CONFIGURATION,
aggregateOperation: AggregateOperations.MIN,
};
const result = convertAggregateOperationForDateField(config, undefined);
expect(result).toBeUndefined();
});
it('returns undefined when field is not found', () => {
const config: ChartConfiguration = {
...TEST_BAR_CHART_CONFIGURATION,
aggregateFieldMetadataId: 'missing-field',
aggregateOperation: AggregateOperations.MIN,
};
const objectMetadataItem = createMockObjectMetadataItem([
{ id: 'other-field', type: FieldMetadataType.DATE },
]);
const result = convertAggregateOperationForDateField(
config,
objectMetadataItem,
);
expect(result).toBeUndefined();
});
});
@@ -0,0 +1,47 @@
import { convertBarOrLineChartConfigToPieChart } from '@/command-menu/pages/page-layout/utils/convertBarOrLineChartConfigToPieChart';
import { type BarChartConfiguration } from '~/generated/graphql';
import {
TEST_BAR_CHART_CONFIGURATION,
TEST_LINE_CHART_CONFIGURATION,
TEST_PIE_CHART_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('convertBarOrLineChartConfigToPieChart', () => {
it('maps bar chart fields to pie chart equivalents', () => {
const result = convertBarOrLineChartConfigToPieChart(
TEST_BAR_CHART_CONFIGURATION,
);
expect(result).toEqual({
groupByFieldMetadataId:
TEST_BAR_CHART_CONFIGURATION.primaryAxisGroupByFieldMetadataId,
groupBySubFieldName:
TEST_BAR_CHART_CONFIGURATION.primaryAxisGroupBySubFieldName,
dateGranularity: TEST_BAR_CHART_CONFIGURATION.primaryAxisDateGranularity,
orderBy: TEST_BAR_CHART_CONFIGURATION.primaryAxisOrderBy,
});
});
it('maps line chart fields to pie chart equivalents', () => {
const result = convertBarOrLineChartConfigToPieChart(
TEST_LINE_CHART_CONFIGURATION,
);
expect(result).toEqual({
groupByFieldMetadataId:
TEST_LINE_CHART_CONFIGURATION.primaryAxisGroupByFieldMetadataId,
groupBySubFieldName:
TEST_LINE_CHART_CONFIGURATION.primaryAxisGroupBySubFieldName,
dateGranularity: TEST_LINE_CHART_CONFIGURATION.primaryAxisDateGranularity,
orderBy: TEST_LINE_CHART_CONFIGURATION.primaryAxisOrderBy,
});
});
it('returns empty object for non-bar/line chart configuration', () => {
const result = convertBarOrLineChartConfigToPieChart(
TEST_PIE_CHART_CONFIGURATION as unknown as BarChartConfiguration,
);
expect(result).toEqual({});
});
});
@@ -0,0 +1,50 @@
import { convertPieChartConfigToBarOrLineChart } from '@/command-menu/pages/page-layout/utils/convertPieChartConfigToBarOrLineChart';
import { type PieChartConfiguration } from '~/generated/graphql';
import {
TEST_BAR_CHART_CONFIGURATION,
TEST_PIE_CHART_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('convertPieChartConfigToBarOrLineChart', () => {
it('maps pie chart fields to bar/line chart equivalents', () => {
const result = convertPieChartConfigToBarOrLineChart(
TEST_PIE_CHART_CONFIGURATION,
);
expect(result).toEqual({
primaryAxisGroupByFieldMetadataId:
TEST_PIE_CHART_CONFIGURATION.groupByFieldMetadataId,
primaryAxisGroupBySubFieldName:
TEST_PIE_CHART_CONFIGURATION.groupBySubFieldName,
primaryAxisDateGranularity: TEST_PIE_CHART_CONFIGURATION.dateGranularity,
primaryAxisOrderBy: TEST_PIE_CHART_CONFIGURATION.orderBy,
});
});
it('handles null/undefined fields', () => {
const minimalPieConfig: PieChartConfiguration = {
...TEST_PIE_CHART_CONFIGURATION,
groupByFieldMetadataId: undefined as unknown as string,
groupBySubFieldName: null,
dateGranularity: null,
orderBy: null,
};
const result = convertPieChartConfigToBarOrLineChart(minimalPieConfig);
expect(result).toEqual({
primaryAxisGroupByFieldMetadataId: undefined,
primaryAxisGroupBySubFieldName: null,
primaryAxisDateGranularity: null,
primaryAxisOrderBy: null,
});
});
it('returns empty object for non-pie chart configuration', () => {
const result = convertPieChartConfigToBarOrLineChart(
TEST_BAR_CHART_CONFIGURATION as unknown as PieChartConfiguration,
);
expect(result).toEqual({});
});
});
@@ -17,14 +17,14 @@ import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/se
import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting';
import { SORT_BY_GROUP_BY_FIELD_SETTING } from '@/command-menu/pages/page-layout/constants/settings/SortByGroupByFieldSetting';
import { STACKED_BARS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedBarsSetting';
import { IconAxisX, IconAxisY } from 'twenty-ui/display';
import { GraphType } from '~/generated-metadata/graphql';
import { getBarChartSettings } from '@/command-menu/pages/page-layout/utils/getBarChartSettings';
import { IconAxisX, IconAxisY } from 'twenty-ui/display';
import { BarChartLayout } from '~/generated/graphql';
describe('getBarChartSettings', () => {
describe('Vertical bar chart', () => {
it('should place primary axis items under "X axis" heading', () => {
const result = getBarChartSettings(GraphType.VERTICAL_BAR);
const result = getBarChartSettings(BarChartLayout.VERTICAL);
const xAxisGroup = result.find(
(group) => group.heading.id === CHART_SETTINGS_HEADINGS.X_AXIS.id,
@@ -41,7 +41,7 @@ describe('getBarChartSettings', () => {
});
it('should place secondary axis items under "Y axis" heading', () => {
const result = getBarChartSettings(GraphType.VERTICAL_BAR);
const result = getBarChartSettings(BarChartLayout.VERTICAL);
const yAxisGroup = result.find(
(group) => group.heading.id === CHART_SETTINGS_HEADINGS.Y_AXIS.id,
@@ -61,7 +61,7 @@ describe('getBarChartSettings', () => {
});
it('should have all expected groups in correct order', () => {
const result = getBarChartSettings(GraphType.VERTICAL_BAR);
const result = getBarChartSettings(BarChartLayout.VERTICAL);
expect(result).toHaveLength(4);
expect(result[0].heading).toBe(CHART_SETTINGS_HEADINGS.DATA);
@@ -73,7 +73,7 @@ describe('getBarChartSettings', () => {
describe('Horizontal bar chart', () => {
it('should place SECONDARY axis items under "X axis" heading', () => {
const result = getBarChartSettings(GraphType.HORIZONTAL_BAR);
const result = getBarChartSettings(BarChartLayout.HORIZONTAL);
const xAxisGroup = result.find(
(group) => group.heading.id === CHART_SETTINGS_HEADINGS.X_AXIS.id,
@@ -93,7 +93,7 @@ describe('getBarChartSettings', () => {
});
it('should place PRIMARY axis items under "Y axis" heading', () => {
const result = getBarChartSettings(GraphType.HORIZONTAL_BAR);
const result = getBarChartSettings(BarChartLayout.HORIZONTAL);
const yAxisGroup = result.find(
(group) => group.heading.id === CHART_SETTINGS_HEADINGS.Y_AXIS.id,
@@ -110,7 +110,7 @@ describe('getBarChartSettings', () => {
});
it('should have all expected groups in correct order', () => {
const result = getBarChartSettings(GraphType.HORIZONTAL_BAR);
const result = getBarChartSettings(BarChartLayout.HORIZONTAL);
expect(result).toHaveLength(4);
expect(result[0].heading).toBe(CHART_SETTINGS_HEADINGS.DATA);
@@ -122,8 +122,8 @@ describe('getBarChartSettings', () => {
describe('Common groups', () => {
it('should have consistent Data group for both orientations', () => {
const verticalResult = getBarChartSettings(GraphType.VERTICAL_BAR);
const horizontalResult = getBarChartSettings(GraphType.HORIZONTAL_BAR);
const verticalResult = getBarChartSettings(BarChartLayout.VERTICAL);
const horizontalResult = getBarChartSettings(BarChartLayout.HORIZONTAL);
const verticalDataGroup = verticalResult.find(
(group) => group.heading.id === CHART_SETTINGS_HEADINGS.DATA.id,
@@ -140,8 +140,8 @@ describe('getBarChartSettings', () => {
});
it('should have consistent Style group for both orientations', () => {
const verticalResult = getBarChartSettings(GraphType.VERTICAL_BAR);
const horizontalResult = getBarChartSettings(GraphType.HORIZONTAL_BAR);
const verticalResult = getBarChartSettings(BarChartLayout.VERTICAL);
const horizontalResult = getBarChartSettings(BarChartLayout.HORIZONTAL);
const verticalStyleGroup = verticalResult.find(
(group) => group.heading.id === CHART_SETTINGS_HEADINGS.STYLE.id,
@@ -0,0 +1,67 @@
import { getChartLimitMessage } from '@/command-menu/pages/page-layout/utils/getChartLimitMessage';
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
import { WidgetConfigurationType } from '~/generated/graphql';
describe('getChartLimitMessage', () => {
it('returns date-based message for bar chart with date axis', () => {
const result = getChartLimitMessage({
widgetConfigurationType: WidgetConfigurationType.BAR_CHART,
isPrimaryAxisDate: true,
primaryAxisDateGranularity: ObjectRecordGroupByDateGranularity.DAY,
});
expect(result).toContain('Undisplayed data');
expect(result).toContain('days');
expect(result).toContain('per chart');
});
it('returns bars message for bar chart without date axis', () => {
const result = getChartLimitMessage({
widgetConfigurationType: WidgetConfigurationType.BAR_CHART,
isPrimaryAxisDate: false,
primaryAxisDateGranularity: null,
});
expect(result).toContain('bars per chart');
});
it('returns data points message for line chart without date axis', () => {
const result = getChartLimitMessage({
widgetConfigurationType: WidgetConfigurationType.LINE_CHART,
isPrimaryAxisDate: false,
primaryAxisDateGranularity: null,
});
expect(result).toContain('data points per chart');
});
it('returns slices message for pie chart', () => {
const result = getChartLimitMessage({
widgetConfigurationType: WidgetConfigurationType.PIE_CHART,
isPrimaryAxisDate: false,
primaryAxisDateGranularity: null,
});
expect(result).toContain('slices per chart');
});
it('returns date-based message with weeks granularity', () => {
const result = getChartLimitMessage({
widgetConfigurationType: WidgetConfigurationType.LINE_CHART,
isPrimaryAxisDate: true,
primaryAxisDateGranularity: ObjectRecordGroupByDateGranularity.WEEK,
});
expect(result).toContain('weeks');
});
it('returns slices message when isPrimaryAxisDate is true but granularity is null', () => {
const result = getChartLimitMessage({
widgetConfigurationType: WidgetConfigurationType.PIE_CHART,
isPrimaryAxisDate: true,
primaryAxisDateGranularity: null,
});
expect(result).toContain('slices per chart');
});
});
@@ -0,0 +1,46 @@
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { getConfigurationTypeFromGraphType } from '@/command-menu/pages/page-layout/utils/getConfigurationTypeFromGraphType';
import { WidgetConfigurationType } from '~/generated/graphql';
describe('getConfigurationTypeFromGraphType', () => {
it('returns BAR_CHART for VERTICAL_BAR', () => {
expect(getConfigurationTypeFromGraphType(GraphType.VERTICAL_BAR)).toBe(
WidgetConfigurationType.BAR_CHART,
);
});
it('returns BAR_CHART for HORIZONTAL_BAR', () => {
expect(getConfigurationTypeFromGraphType(GraphType.HORIZONTAL_BAR)).toBe(
WidgetConfigurationType.BAR_CHART,
);
});
it('returns LINE_CHART for LINE', () => {
expect(getConfigurationTypeFromGraphType(GraphType.LINE)).toBe(
WidgetConfigurationType.LINE_CHART,
);
});
it('returns PIE_CHART for PIE', () => {
expect(getConfigurationTypeFromGraphType(GraphType.PIE)).toBe(
WidgetConfigurationType.PIE_CHART,
);
});
it('returns AGGREGATE_CHART for AGGREGATE', () => {
expect(getConfigurationTypeFromGraphType(GraphType.AGGREGATE)).toBe(
WidgetConfigurationType.AGGREGATE_CHART,
);
});
it('returns GAUGE_CHART for GAUGE', () => {
expect(getConfigurationTypeFromGraphType(GraphType.GAUGE)).toBe(
WidgetConfigurationType.GAUGE_CHART,
);
});
it('throws for unknown graph type', () => {
const unknownGraphType = 'UNKNOWN' as never;
expect(() => getConfigurationTypeFromGraphType(unknownGraphType)).toThrow();
});
});
@@ -0,0 +1,71 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { getCurrentGraphTypeFromConfig } from '@/command-menu/pages/page-layout/utils/getCurrentGraphTypeFromConfig';
import {
TEST_AGGREGATE_CHART_CONFIGURATION,
TEST_BAR_CHART_CONFIGURATION,
TEST_BAR_CHART_CONFIGURATION_HORIZONTAL,
TEST_GAUGE_CHART_CONFIGURATION,
TEST_LINE_CHART_CONFIGURATION,
TEST_PIE_CHART_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('getCurrentGraphTypeFromConfig', () => {
it('returns VERTICAL_BAR for bar chart with vertical layout', () => {
expect(
getCurrentGraphTypeFromConfig(
TEST_BAR_CHART_CONFIGURATION as ChartConfiguration,
),
).toBe(GraphType.VERTICAL_BAR);
});
it('returns HORIZONTAL_BAR for bar chart with horizontal layout', () => {
expect(
getCurrentGraphTypeFromConfig(
TEST_BAR_CHART_CONFIGURATION_HORIZONTAL as ChartConfiguration,
),
).toBe(GraphType.HORIZONTAL_BAR);
});
it('returns LINE for line chart', () => {
expect(
getCurrentGraphTypeFromConfig(
TEST_LINE_CHART_CONFIGURATION as ChartConfiguration,
),
).toBe(GraphType.LINE);
});
it('returns PIE for pie chart', () => {
expect(
getCurrentGraphTypeFromConfig(
TEST_PIE_CHART_CONFIGURATION as ChartConfiguration,
),
).toBe(GraphType.PIE);
});
it('returns AGGREGATE for aggregate chart', () => {
expect(
getCurrentGraphTypeFromConfig(
TEST_AGGREGATE_CHART_CONFIGURATION as ChartConfiguration,
),
).toBe(GraphType.AGGREGATE);
});
it('returns GAUGE for gauge chart', () => {
expect(
getCurrentGraphTypeFromConfig(
TEST_GAUGE_CHART_CONFIGURATION as ChartConfiguration,
),
).toBe(GraphType.GAUGE);
});
it('throws for unknown configuration type', () => {
const unknownConfig = {
__typename: 'UnknownConfiguration',
} as unknown as ChartConfiguration;
expect(() => getCurrentGraphTypeFromConfig(unknownConfig)).toThrow(
'Unknown chart configuration type',
);
});
});
@@ -0,0 +1,64 @@
import { getDateGranularityPluralLabel } from '@/command-menu/pages/page-layout/utils/getDateGranularityPluralLabel';
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
describe('getDateGranularityPluralLabel', () => {
it('returns "days" for DAY granularity', () => {
expect(
getDateGranularityPluralLabel(ObjectRecordGroupByDateGranularity.DAY),
).toBe('days');
});
it('returns "weeks" for WEEK granularity', () => {
expect(
getDateGranularityPluralLabel(ObjectRecordGroupByDateGranularity.WEEK),
).toBe('weeks');
});
it('returns "months" for MONTH granularity', () => {
expect(
getDateGranularityPluralLabel(ObjectRecordGroupByDateGranularity.MONTH),
).toBe('months');
});
it('returns "quarters" for QUARTER granularity', () => {
expect(
getDateGranularityPluralLabel(ObjectRecordGroupByDateGranularity.QUARTER),
).toBe('quarters');
});
it('returns "years" for YEAR granularity', () => {
expect(
getDateGranularityPluralLabel(ObjectRecordGroupByDateGranularity.YEAR),
).toBe('years');
});
it('returns "days" for DAY_OF_THE_WEEK granularity', () => {
expect(
getDateGranularityPluralLabel(
ObjectRecordGroupByDateGranularity.DAY_OF_THE_WEEK,
),
).toBe('days');
});
it('returns "months" for MONTH_OF_THE_YEAR granularity', () => {
expect(
getDateGranularityPluralLabel(
ObjectRecordGroupByDateGranularity.MONTH_OF_THE_YEAR,
),
).toBe('months');
});
it('returns "quarters" for QUARTER_OF_THE_YEAR granularity', () => {
expect(
getDateGranularityPluralLabel(
ObjectRecordGroupByDateGranularity.QUARTER_OF_THE_YEAR,
),
).toBe('quarters');
});
it('returns "items" for NONE granularity', () => {
expect(
getDateGranularityPluralLabel(ObjectRecordGroupByDateGranularity.NONE),
).toBe('items');
});
});
@@ -1,31 +0,0 @@
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
} from '~/generated/graphql';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
describe('isAggregateChartConfiguration', () => {
it('should return true for AggregateChartConfiguration', () => {
const configuration = {
__typename: 'AggregateChartConfiguration',
} as AggregateChartConfiguration;
expect(isAggregateChartConfiguration(configuration)).toBe(true);
});
it('should return false for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isAggregateChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isAggregateChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isAggregateChartConfiguration(undefined)).toBe(false);
});
});
@@ -1,31 +0,0 @@
import {
type BarChartConfiguration,
type LineChartConfiguration,
} from '~/generated/graphql';
import { isBarChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarChartConfiguration';
describe('isBarChartConfiguration', () => {
it('should return true for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration' as const,
} as BarChartConfiguration;
expect(isBarChartConfiguration(configuration)).toBe(true);
});
it('should return false for LineChartConfiguration', () => {
const configuration = {
__typename: 'LineChartConfiguration' as const,
} as LineChartConfiguration;
expect(isBarChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isBarChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isBarChartConfiguration(undefined)).toBe(false);
});
});
@@ -1,40 +0,0 @@
import {
type BarChartConfiguration,
type LineChartConfiguration,
type PieChartConfiguration,
} from '~/generated/graphql';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
describe('isBarOrLineChartConfiguration', () => {
it('should return true for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isBarOrLineChartConfiguration(configuration)).toBe(true);
});
it('should return true for LineChartConfiguration', () => {
const configuration = {
__typename: 'LineChartConfiguration',
} as LineChartConfiguration;
expect(isBarOrLineChartConfiguration(configuration)).toBe(true);
});
it('should return false for PieChartConfiguration', () => {
const configuration = {
__typename: 'PieChartConfiguration',
} as PieChartConfiguration;
expect(isBarOrLineChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isBarOrLineChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isBarOrLineChartConfiguration(undefined)).toBe(false);
});
});
@@ -1,76 +0,0 @@
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type GaugeChartConfiguration,
type IframeConfiguration,
type LineChartConfiguration,
type PieChartConfiguration,
type StandaloneRichTextConfiguration,
} from '~/generated/graphql';
import { isChartConfiguration } from '@/command-menu/pages/page-layout/utils/isChartConfiguration';
describe('isChartConfiguration', () => {
it('should return true for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isChartConfiguration(configuration)).toBe(true);
});
it('should return true for LineChartConfiguration', () => {
const configuration = {
__typename: 'LineChartConfiguration',
} as LineChartConfiguration;
expect(isChartConfiguration(configuration)).toBe(true);
});
it('should return true for PieChartConfiguration', () => {
const configuration = {
__typename: 'PieChartConfiguration',
} as PieChartConfiguration;
expect(isChartConfiguration(configuration)).toBe(true);
});
it('should return true for AggregateChartConfiguration', () => {
const configuration = {
__typename: 'AggregateChartConfiguration',
} as AggregateChartConfiguration;
expect(isChartConfiguration(configuration)).toBe(true);
});
it('should return true for GaugeChartConfiguration', () => {
const configuration = {
__typename: 'GaugeChartConfiguration',
} as GaugeChartConfiguration;
expect(isChartConfiguration(configuration)).toBe(true);
});
it('should return false for IframeConfiguration', () => {
const configuration = {
__typename: 'IframeConfiguration',
} as IframeConfiguration;
expect(isChartConfiguration(configuration)).toBe(false);
});
it('should return false for StandaloneRichTextConfiguration', () => {
const configuration = {
__typename: 'StandaloneRichTextConfiguration',
} as StandaloneRichTextConfiguration;
expect(isChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isChartConfiguration(undefined)).toBe(false);
});
});
@@ -0,0 +1,51 @@
import { isChartWidget } from '@/command-menu/pages/page-layout/utils/isChartWidget';
import {
createTestWidget,
TEST_BAR_CHART_CONFIGURATION,
TEST_FIELDS_CONFIGURATION,
TEST_IFRAME_CONFIGURATION,
TEST_LINE_CHART_CONFIGURATION,
TEST_PIE_CHART_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('isChartWidget', () => {
it('returns true for widget with BarChartConfiguration', () => {
const widget = createTestWidget({
configuration: TEST_BAR_CHART_CONFIGURATION,
});
expect(isChartWidget(widget)).toBe(true);
});
it('returns true for widget with LineChartConfiguration', () => {
const widget = createTestWidget({
configuration: TEST_LINE_CHART_CONFIGURATION,
});
expect(isChartWidget(widget)).toBe(true);
});
it('returns true for widget with PieChartConfiguration', () => {
const widget = createTestWidget({
configuration: TEST_PIE_CHART_CONFIGURATION,
});
expect(isChartWidget(widget)).toBe(true);
});
it('returns false for widget with IframeConfiguration', () => {
const widget = createTestWidget({
configuration: TEST_IFRAME_CONFIGURATION,
});
expect(isChartWidget(widget)).toBe(false);
});
it('returns false for widget with FieldsConfiguration', () => {
const widget = createTestWidget({
configuration: TEST_FIELDS_CONFIGURATION,
});
expect(isChartWidget(widget)).toBe(false);
});
});
@@ -1,31 +0,0 @@
import {
type BarChartConfiguration,
type GaugeChartConfiguration,
} from '~/generated/graphql';
import { isGaugeChartConfiguration } from '@/command-menu/pages/page-layout/utils/isGaugeChartConfiguration';
describe('isGaugeChartConfiguration', () => {
it('should return true for GaugeChartConfiguration', () => {
const configuration = {
__typename: 'GaugeChartConfiguration',
} as GaugeChartConfiguration;
expect(isGaugeChartConfiguration(configuration)).toBe(true);
});
it('should return false for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isGaugeChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isGaugeChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isGaugeChartConfiguration(undefined)).toBe(false);
});
});
@@ -1,31 +0,0 @@
import {
type BarChartConfiguration,
type IframeConfiguration,
} from '~/generated/graphql';
import { isIframeConfiguration } from '@/command-menu/pages/page-layout/utils/isIframeConfiguration';
describe('isIframeConfiguration', () => {
it('should return true for IframeConfiguration', () => {
const configuration = {
__typename: 'IframeConfiguration',
} as IframeConfiguration;
expect(isIframeConfiguration(configuration)).toBe(true);
});
it('should return false for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isIframeConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isIframeConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isIframeConfiguration(undefined)).toBe(false);
});
});
@@ -1,31 +0,0 @@
import {
type BarChartConfiguration,
type LineChartConfiguration,
} from '~/generated/graphql';
import { isLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isLineChartConfiguration';
describe('isLineChartConfiguration', () => {
it('should return true for LineChartConfiguration', () => {
const configuration = {
__typename: 'LineChartConfiguration',
} as LineChartConfiguration;
expect(isLineChartConfiguration(configuration)).toBe(true);
});
it('should return false for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isLineChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isLineChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isLineChartConfiguration(undefined)).toBe(false);
});
});
@@ -1,12 +1,13 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { isMinMaxRangeValid } from '@/command-menu/pages/page-layout/utils/isMinMaxRangeValid';
import { GraphType } from '~/generated/graphql';
import { BarChartLayout, WidgetConfigurationType } from '~/generated/graphql';
describe('isMinMaxRangeValid', () => {
const mockConfiguration = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMin: 10,
rangeMax: 100,
} as ChartConfiguration;
@@ -78,7 +79,8 @@ describe('isMinMaxRangeValid', () => {
it('should be valid when new rangeMin is negative and greater than existing rangeMax', () => {
const configWithNegatives = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMin: -100,
rangeMax: -10,
} as ChartConfiguration;
@@ -101,7 +103,8 @@ describe('isMinMaxRangeValid', () => {
it('should be valid when new rangeMin is zero and greater than existing rangeMax', () => {
const configWithZero = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMin: 0,
rangeMax: 100,
} as ChartConfiguration;
@@ -119,7 +122,8 @@ describe('isMinMaxRangeValid', () => {
it('should be valid when setting rangeMin on configuration without any range values', () => {
const emptyConfig = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
} as ChartConfiguration;
const result = isMinMaxRangeValid(
@@ -134,7 +138,8 @@ describe('isMinMaxRangeValid', () => {
it('should be valid when setting rangeMax on configuration without any range values', () => {
const emptyConfig = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
} as ChartConfiguration;
const result = isMinMaxRangeValid(
@@ -149,7 +154,8 @@ describe('isMinMaxRangeValid', () => {
it('should be valid when setting rangeMin without existing rangeMax', () => {
const configWithOnlyMin = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMin: 10,
} as ChartConfiguration;
@@ -165,7 +171,8 @@ describe('isMinMaxRangeValid', () => {
it('should be valid when setting rangeMax without existing rangeMin', () => {
const configWithOnlyMax = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMax: 100,
} as ChartConfiguration;
@@ -181,7 +188,8 @@ describe('isMinMaxRangeValid', () => {
it('should be invalid when setting rangeMin that would exceed existing rangeMax', () => {
const configWithOnlyMax = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMax: 100,
} as ChartConfiguration;
@@ -197,7 +205,8 @@ describe('isMinMaxRangeValid', () => {
it('should be invalid when setting rangeMax that would be less than existing rangeMin', () => {
const configWithOnlyMin = {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
rangeMin: 50,
} as ChartConfiguration;
@@ -1,31 +0,0 @@
import {
type BarChartConfiguration,
type PieChartConfiguration,
} from '~/generated/graphql';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
describe('isPieChartConfiguration', () => {
it('should return true for PieChartConfiguration', () => {
const configuration = {
__typename: 'PieChartConfiguration',
} as PieChartConfiguration;
expect(isPieChartConfiguration(configuration)).toBe(true);
});
it('should return false for BarChartConfiguration', () => {
const configuration = {
__typename: 'BarChartConfiguration',
} as BarChartConfiguration;
expect(isPieChartConfiguration(configuration)).toBe(false);
});
it('should return false for null', () => {
expect(isPieChartConfiguration(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isPieChartConfiguration(undefined)).toBe(false);
});
});
@@ -0,0 +1,75 @@
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import {
ALL_CHART_CONFIGURATIONS,
TEST_BAR_CHART_CONFIGURATION,
TEST_IFRAME_CONFIGURATION,
TEST_PIE_CHART_CONFIGURATION,
TEST_STANDALONE_RICH_TEXT_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('isWidgetConfigurationOfType', () => {
it('returns true when __typename matches', () => {
expect(
isWidgetConfigurationOfType(
TEST_BAR_CHART_CONFIGURATION,
'BarChartConfiguration',
),
).toBe(true);
});
it('returns false when __typename does not match', () => {
expect(
isWidgetConfigurationOfType(
TEST_BAR_CHART_CONFIGURATION,
'PieChartConfiguration',
),
).toBe(false);
});
it('returns false for null configuration', () => {
expect(isWidgetConfigurationOfType(null, 'BarChartConfiguration')).toBe(
false,
);
});
it('returns false for undefined configuration', () => {
expect(
isWidgetConfigurationOfType(undefined, 'BarChartConfiguration'),
).toBe(false);
});
it('correctly identifies PieChartConfiguration', () => {
expect(
isWidgetConfigurationOfType(
TEST_PIE_CHART_CONFIGURATION,
'PieChartConfiguration',
),
).toBe(true);
});
it('correctly identifies IframeConfiguration', () => {
expect(
isWidgetConfigurationOfType(
TEST_IFRAME_CONFIGURATION,
'IframeConfiguration',
),
).toBe(true);
});
it('correctly identifies StandaloneRichTextConfiguration', () => {
expect(
isWidgetConfigurationOfType(
TEST_STANDALONE_RICH_TEXT_CONFIGURATION,
'StandaloneRichTextConfiguration',
),
).toBe(true);
});
it('works with all chart configuration types', () => {
ALL_CHART_CONFIGURATIONS.forEach((config) => {
expect(isWidgetConfigurationOfType(config, config.__typename!)).toBe(
true,
);
});
});
});
@@ -0,0 +1,41 @@
import { isWidgetConfigurationOfTypeGraph } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfTypeGraph';
import {
ALL_CHART_CONFIGURATIONS,
TEST_FIELDS_CONFIGURATION,
TEST_IFRAME_CONFIGURATION,
TEST_STANDALONE_RICH_TEXT_CONFIGURATION,
} from '~/testing/mock-data/widget-configurations';
describe('isWidgetConfigurationOfTypeGraph', () => {
it('returns true for all chart configurations', () => {
ALL_CHART_CONFIGURATIONS.forEach((config) => {
expect(isWidgetConfigurationOfTypeGraph(config)).toBe(true);
});
});
it('returns false for IframeConfiguration', () => {
expect(isWidgetConfigurationOfTypeGraph(TEST_IFRAME_CONFIGURATION)).toBe(
false,
);
});
it('returns false for StandaloneRichTextConfiguration', () => {
expect(
isWidgetConfigurationOfTypeGraph(TEST_STANDALONE_RICH_TEXT_CONFIGURATION),
).toBe(false);
});
it('returns false for FieldsConfiguration', () => {
expect(isWidgetConfigurationOfTypeGraph(TEST_FIELDS_CONFIGURATION)).toBe(
false,
);
});
it('returns false for null', () => {
expect(isWidgetConfigurationOfTypeGraph(null)).toBe(false);
});
it('returns false for undefined', () => {
expect(isWidgetConfigurationOfTypeGraph(undefined)).toBe(false);
});
});
@@ -1,8 +1,6 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { isBarChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarChartConfiguration';
import { isFieldOrRelationNestedFieldDateKind } from '@/command-menu/pages/page-layout/utils/isFieldOrNestedFieldDateKind';
import { isLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -40,9 +38,18 @@ export const buildChartGroupByFieldConfigUpdate = <
[subFieldNameKey]: subFieldName,
};
const isBarChart = isBarChartConfiguration(configuration);
const isLineChart = isLineChartConfiguration(configuration);
const isPieChart = isPieChartConfiguration(configuration);
const isBarChart = isWidgetConfigurationOfType(
configuration,
'BarChartConfiguration',
);
const isLineChart = isWidgetConfigurationOfType(
configuration,
'LineChartConfiguration',
);
const isPieChart = isWidgetConfigurationOfType(
configuration,
'PieChartConfiguration',
);
if (isPrimaryAxis) {
const existingOrderBy =
@@ -1,11 +1,11 @@
import { type BarLineChartConvertibleFields } from '@/command-menu/pages/page-layout/types/BarLineChartConvertibleFields';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type PieChartConfiguration } from '~/generated/graphql';
export const convertPieChartConfigToBarOrLineChart = (
configuration: PieChartConfiguration,
): BarLineChartConvertibleFields => {
if (!isPieChartConfiguration(configuration)) {
if (!isWidgetConfigurationOfType(configuration, 'PieChartConfiguration')) {
return {};
}
@@ -19,12 +19,12 @@ import { SORT_BY_GROUP_BY_FIELD_SETTING } from '@/command-menu/pages/page-layout
import { STACKED_BARS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedBarsSetting';
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
import { IconAxisX, IconAxisY } from 'twenty-ui/display';
import { GraphType } from '~/generated-metadata/graphql';
import { BarChartLayout } from '~/generated/graphql';
export const getBarChartSettings = (
graphType: GraphType.VERTICAL_BAR | GraphType.HORIZONTAL_BAR,
layout: BarChartLayout,
): ChartSettingsGroup[] => {
const isHorizontal = graphType === GraphType.HORIZONTAL_BAR;
const isHorizontal = layout === BarChartLayout.HORIZONTAL;
const dataDisplayXIcon = isHorizontal ? IconAxisY : IconAxisX;
const dataDisplayYIcon = isHorizontal ? IconAxisX : IconAxisY;
@@ -5,11 +5,10 @@ import { PIE_CHART_MAXIMUM_NUMBER_OF_SLICES } from '@/page-layout/widgets/graph/
import { t } from '@lingui/core/macro';
import { type ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { GraphType } from '~/generated/graphql';
import { WidgetConfigurationType } from '~/generated/graphql';
type GetChartLimitMessageParams = {
graphType: GraphType;
widgetConfigurationType: WidgetConfigurationType;
isPrimaryAxisDate: boolean;
primaryAxisDateGranularity:
| ObjectRecordGroupByDateGranularity
@@ -18,15 +17,14 @@ type GetChartLimitMessageParams = {
};
export const getChartLimitMessage = ({
graphType,
widgetConfigurationType,
isPrimaryAxisDate,
primaryAxisDateGranularity,
}: GetChartLimitMessageParams): string => {
const maxItems =
graphType === GraphType.LINE
widgetConfigurationType === WidgetConfigurationType.LINE_CHART
? LINE_CHART_CONSTANTS.MAXIMUM_NUMBER_OF_DATA_POINTS
: graphType === GraphType.VERTICAL_BAR ||
graphType === GraphType.HORIZONTAL_BAR
: widgetConfigurationType === WidgetConfigurationType.BAR_CHART
? BAR_CHART_CONSTANTS.MAXIMUM_NUMBER_OF_BARS
: PIE_CHART_MAXIMUM_NUMBER_OF_SLICES;
@@ -37,14 +35,11 @@ export const getChartLimitMessage = ({
return t`Undisplayed data: max ${maxItems} ${granularityLabel} per chart.`;
}
if (graphType === GraphType.LINE) {
if (widgetConfigurationType === WidgetConfigurationType.LINE_CHART) {
return t`Undisplayed data: max ${maxItems} data points per chart.`;
}
if (
graphType === GraphType.VERTICAL_BAR ||
graphType === GraphType.HORIZONTAL_BAR
) {
if (widgetConfigurationType === WidgetConfigurationType.BAR_CHART) {
return t`Undisplayed data: max ${maxItems} bars per chart.`;
}
@@ -0,0 +1,23 @@
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { assertUnreachable } from 'twenty-shared/utils';
import { WidgetConfigurationType } from '~/generated/graphql';
export const getConfigurationTypeFromGraphType = (
graphType: GraphType,
): WidgetConfigurationType => {
switch (graphType) {
case GraphType.VERTICAL_BAR:
case GraphType.HORIZONTAL_BAR:
return WidgetConfigurationType.BAR_CHART;
case GraphType.LINE:
return WidgetConfigurationType.LINE_CHART;
case GraphType.PIE:
return WidgetConfigurationType.PIE_CHART;
case GraphType.AGGREGATE:
return WidgetConfigurationType.AGGREGATE_CHART;
case GraphType.GAUGE:
return WidgetConfigurationType.GAUGE_CHART;
default:
assertUnreachable(graphType);
}
};
@@ -0,0 +1,35 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { t } from '@lingui/core/macro';
import { BarChartLayout } from '~/generated/graphql';
export const getCurrentGraphTypeFromConfig = (
configuration: ChartConfiguration,
): GraphType => {
if (isWidgetConfigurationOfType(configuration, 'BarChartConfiguration')) {
return configuration.layout === BarChartLayout.HORIZONTAL
? GraphType.HORIZONTAL_BAR
: GraphType.VERTICAL_BAR;
}
if (isWidgetConfigurationOfType(configuration, 'LineChartConfiguration')) {
return GraphType.LINE;
}
if (isWidgetConfigurationOfType(configuration, 'PieChartConfiguration')) {
return GraphType.PIE;
}
if (
isWidgetConfigurationOfType(configuration, 'AggregateChartConfiguration')
) {
return GraphType.AGGREGATE;
}
if (isWidgetConfigurationOfType(configuration, 'GaugeChartConfiguration')) {
return GraphType.GAUGE;
}
throw new Error(t`Unknown chart configuration type`);
};
@@ -1,17 +0,0 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type AggregateChartConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
export const isAggregateChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is AggregateChartConfiguration => {
return configuration?.__typename === 'AggregateChartConfiguration';
};
@@ -1,17 +0,0 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type BarChartConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
export const isBarChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is BarChartConfiguration => {
return configuration?.__typename === 'BarChartConfiguration';
};
@@ -1,24 +0,0 @@
import {
type BarChartConfiguration,
type LineChartConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import { isBarChartConfiguration } from './isBarChartConfiguration';
import { isLineChartConfiguration } from './isLineChartConfiguration';
export const isBarOrLineChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is BarChartConfiguration | LineChartConfiguration => {
return (
isBarChartConfiguration(configuration) ||
isLineChartConfiguration(configuration)
);
};
@@ -1,27 +0,0 @@
import { type WidgetConfiguration } from '~/generated/graphql';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
import { isBarChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarChartConfiguration';
import { isGaugeChartConfiguration } from '@/command-menu/pages/page-layout/utils/isGaugeChartConfiguration';
import { isLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
export const isChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is ChartConfiguration => {
return (
isBarChartConfiguration(configuration) ||
isLineChartConfiguration(configuration) ||
isPieChartConfiguration(configuration) ||
isAggregateChartConfiguration(configuration) ||
isGaugeChartConfiguration(configuration)
);
};
@@ -1,8 +1,13 @@
import { type ChartWidget } from '@/command-menu/pages/page-layout/types/ChartWidget';
import { WidgetType } from '~/generated/graphql';
import { isWidgetConfigurationOfTypeGraph } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfTypeGraph';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { type WidgetConfiguration } from '~/generated/graphql';
export const isChartWidget = (
pageLayoutWidget: any,
pageLayoutWidget: PageLayoutWidget,
): pageLayoutWidget is ChartWidget => {
return pageLayoutWidget.type === WidgetType.GRAPH;
return isWidgetConfigurationOfTypeGraph(
// TODO: Remove this cast when we FieldsConfiguration and FieldConfiguration are in the backend
pageLayoutWidget.configuration as WidgetConfiguration,
);
};
@@ -1,17 +0,0 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type GaugeChartConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
export const isGaugeChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is GaugeChartConfiguration => {
return configuration?.__typename === 'GaugeChartConfiguration';
};
@@ -1,17 +0,0 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type IframeConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
export const isIframeConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is IframeConfiguration => {
return configuration?.__typename === 'IframeConfiguration';
};
@@ -1,17 +0,0 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type LineChartConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
export const isLineChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is LineChartConfiguration => {
return configuration?.__typename === 'LineChartConfiguration';
};
@@ -1,6 +1,6 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { isDefined } from 'twenty-shared/utils';
export const isMinMaxRangeValid = (
@@ -10,7 +10,11 @@ export const isMinMaxRangeValid = (
newValue: number,
configuration: ChartConfiguration,
): boolean => {
if (!isBarOrLineChartConfiguration(configuration)) {
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
if (!isBarOrLineChart) {
return true;
}
@@ -1,17 +0,0 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type PieChartConfiguration,
type WidgetConfiguration,
} from '~/generated/graphql';
export const isPieChartConfiguration = (
configuration:
| WidgetConfiguration
| FieldConfiguration
| FieldsConfiguration
| null
| undefined,
): configuration is PieChartConfiguration => {
return configuration?.__typename === 'PieChartConfiguration';
};
@@ -0,0 +1,65 @@
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type GaugeChartConfiguration,
type IframeConfiguration,
type LineChartConfiguration,
type PieChartConfiguration,
type StandaloneRichTextConfiguration,
type WidgetConfiguration,
type WidgetConfigurationType,
} from '~/generated/graphql';
type WidgetConfigurationTypenameMap = {
AggregateChartConfiguration: Omit<
AggregateChartConfiguration,
'configurationType'
> & {
configurationType: WidgetConfigurationType.AGGREGATE_CHART;
};
BarChartConfiguration: Omit<BarChartConfiguration, 'configurationType'> & {
configurationType: WidgetConfigurationType.BAR_CHART;
};
GaugeChartConfiguration: Omit<
GaugeChartConfiguration,
'configurationType'
> & {
configurationType: WidgetConfigurationType.GAUGE_CHART;
};
IframeConfiguration: Omit<IframeConfiguration, 'configurationType'> & {
configurationType: WidgetConfigurationType.IFRAME;
};
LineChartConfiguration: Omit<LineChartConfiguration, 'configurationType'> & {
configurationType: WidgetConfigurationType.LINE_CHART;
};
PieChartConfiguration: Omit<PieChartConfiguration, 'configurationType'> & {
configurationType: WidgetConfigurationType.PIE_CHART;
};
StandaloneRichTextConfiguration: Omit<
StandaloneRichTextConfiguration,
'configurationType'
> & {
configurationType: WidgetConfigurationType.STANDALONE_RICH_TEXT;
};
};
type WidgetConfigurationTypename = keyof WidgetConfigurationTypenameMap;
export type WidgetConfigurationOfType<T extends WidgetConfigurationTypename> =
WidgetConfigurationTypenameMap[T];
export const isWidgetConfigurationOfType = <
T extends WidgetConfigurationTypename,
>(
configuration:
| WidgetConfiguration
| FieldsConfiguration
| FieldConfiguration
| null
| undefined,
typename: T,
): configuration is WidgetConfigurationTypenameMap[T] => {
return configuration?.__typename === typename;
};
@@ -0,0 +1,22 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type FieldConfiguration } from '@/page-layout/types/FieldConfiguration';
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
import { type WidgetConfiguration } from '~/generated/graphql';
export const isWidgetConfigurationOfTypeGraph = (
configuration:
| WidgetConfiguration
| FieldsConfiguration
| FieldConfiguration
| null
| undefined,
): configuration is ChartConfiguration => {
return (
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'PieChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'AggregateChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'GaugeChartConfiguration')
);
};
@@ -1,8 +1,7 @@
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
import { isRelationNestedFieldDateKind } from '@/page-layout/widgets/graph/utils/isRelationNestedFieldDateKind';
@@ -55,8 +54,12 @@ export const shouldHideChartSetting = (
);
if (isDefined(configuration) && isDefined(objectMetadataItem)) {
const isBarOrLineChart =
isWidgetConfigurationOfType(configuration, 'BarChartConfiguration') ||
isWidgetConfigurationOfType(configuration, 'LineChartConfiguration');
if (item.id === CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_X) {
if (isBarOrLineChartConfiguration(configuration)) {
if (isBarOrLineChart) {
return shouldHideDateGranularityBasedOnFieldType(
configuration.primaryAxisGroupByFieldMetadataId,
configuration.primaryAxisGroupBySubFieldName,
@@ -67,7 +70,7 @@ export const shouldHideChartSetting = (
}
if (item.id === CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_Y) {
if (isBarOrLineChartConfiguration(configuration)) {
if (isBarOrLineChart) {
return shouldHideDateGranularityBasedOnFieldType(
configuration.secondaryAxisGroupByFieldMetadataId,
configuration.secondaryAxisGroupBySubFieldName,
@@ -78,7 +81,7 @@ export const shouldHideChartSetting = (
}
if (item.id === CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY) {
if (isPieChartConfiguration(configuration)) {
if (isWidgetConfigurationOfType(configuration, 'PieChartConfiguration')) {
return shouldHideDateGranularityBasedOnFieldType(
configuration.groupByFieldMetadataId,
configuration.groupBySubFieldName,
@@ -89,7 +92,7 @@ export const shouldHideChartSetting = (
}
if (item.id === CHART_CONFIGURATION_SETTING_IDS.CUMULATIVE) {
if (isBarOrLineChartConfiguration(configuration)) {
if (isBarOrLineChart) {
return shouldHideDateGranularityBasedOnFieldType(
configuration.primaryAxisGroupByFieldMetadataId,
configuration.primaryAxisGroupBySubFieldName,
@@ -100,7 +103,7 @@ export const shouldHideChartSetting = (
}
if (item.id === CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND) {
if (isPieChartConfiguration(configuration)) {
if (isWidgetConfigurationOfType(configuration, 'PieChartConfiguration')) {
return false;
}
}
@@ -14,17 +14,15 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { generateGroupByAggregateQuery } from '@/object-record/record-aggregate/utils/generateGroupByAggregateQuery';
import { PageLayoutRenderer } from '@/page-layout/components/PageLayoutRenderer';
import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
import {
GraphOrderBy,
GraphType,
WidgetType,
} from '~/generated-metadata/graphql';
import { GraphOrderBy, WidgetType } from '~/generated-metadata/graphql';
import {
AggregateOperations,
AxisNameDisplay,
type BarChartConfiguration,
BarChartLayout,
PageLayoutType,
type PageLayoutWidget,
WidgetConfigurationType,
} from '~/generated/graphql';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
@@ -93,14 +91,14 @@ const mixedGraphsPageLayoutMocks = {
},
configuration: {
__typename: 'AggregateChartConfiguration',
graphType: GraphType.AGGREGATE,
configurationType: WidgetConfigurationType.AGGREGATE_CHART,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
},
createdAt: '2024-01-01T00:00:00Z',
updatedAt: '2024-01-01T00:00:00Z',
deletedAt: null,
} as PageLayoutWidget,
} satisfies PageLayoutWidget,
{
__typename: 'PageLayoutWidget',
id: 'gauge-widget',
@@ -117,7 +115,7 @@ const mixedGraphsPageLayoutMocks = {
},
configuration: {
__typename: 'GaugeChartConfiguration',
graphType: GraphType.GAUGE,
configurationType: WidgetConfigurationType.GAUGE_CHART,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
displayDataLabel: false,
@@ -125,7 +123,7 @@ const mixedGraphsPageLayoutMocks = {
createdAt: '2024-01-01T00:00:00Z',
updatedAt: '2024-01-01T00:00:00Z',
deletedAt: null,
} as PageLayoutWidget,
} satisfies PageLayoutWidget,
{
__typename: 'PageLayoutWidget',
id: 'pie-widget',
@@ -142,7 +140,7 @@ const mixedGraphsPageLayoutMocks = {
},
configuration: {
__typename: 'PieChartConfiguration',
graphType: GraphType.PIE,
configurationType: WidgetConfigurationType.PIE_CHART,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
groupByFieldMetadataId: createdAtField.id,
@@ -151,7 +149,7 @@ const mixedGraphsPageLayoutMocks = {
createdAt: '2024-01-01T00:00:00Z',
updatedAt: '2024-01-01T00:00:00Z',
deletedAt: null,
} as PageLayoutWidget,
} satisfies PageLayoutWidget,
{
__typename: 'PageLayoutWidget',
id: 'bar-widget',
@@ -168,7 +166,8 @@ const mixedGraphsPageLayoutMocks = {
},
configuration: {
__typename: 'BarChartConfiguration',
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: nameField.id,
primaryAxisGroupByFieldMetadataId: createdAtField.id,
@@ -1,6 +1,10 @@
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultCompanyRecordPageLayoutId';
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { PageLayoutType, WidgetType } from '~/generated-metadata/graphql';
import {
PageLayoutType,
WidgetConfigurationType,
WidgetType,
} from '~/generated-metadata/graphql';
export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
__typename: 'PageLayout',
@@ -38,7 +42,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -57,7 +65,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -78,6 +90,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'accountOwner',
layout: 'FIELD',
},
@@ -101,6 +114,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'opportunities',
layout: 'FIELD',
},
@@ -124,6 +138,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'people',
layout: 'FIELD',
},
@@ -147,6 +162,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'people',
layout: 'FIELD',
},
@@ -170,6 +186,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'name',
layout: 'FIELD',
},
@@ -193,6 +210,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'name',
layout: 'FIELD',
},
@@ -216,6 +234,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'employees',
layout: 'FIELD',
},
@@ -239,6 +258,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
},
configuration: {
__typename: 'FieldConfiguration',
configurationType: WidgetConfigurationType.FIELD,
fieldMetadataId: 'linkedinLink',
layout: 'FIELD',
},
@@ -274,7 +294,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -307,7 +331,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -340,7 +368,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -373,7 +405,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -406,7 +442,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -439,7 +479,11 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -41,7 +41,11 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
// Note: Configuration is null by default. For testing purposes,
// use useTempNoteFieldsConfiguration() hook at runtime to get
// a configuration with actual field metadata IDs from the backend.
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -60,7 +64,11 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -99,7 +107,11 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -139,7 +151,11 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -172,7 +188,11 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -1,6 +1,10 @@
import { DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultOpportunityRecordPageLayoutId';
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { PageLayoutType, WidgetType } from '~/generated/graphql';
import {
PageLayoutType,
WidgetConfigurationType,
WidgetType,
} from '~/generated/graphql';
export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
__typename: 'PageLayout',
@@ -38,7 +42,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -71,7 +79,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -104,7 +116,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -137,7 +153,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -170,7 +190,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -203,7 +227,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -236,7 +264,11 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: WidgetConfigurationType.FIELDS,
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -38,7 +38,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -71,7 +75,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -104,7 +112,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -137,7 +149,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -170,7 +186,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -203,7 +223,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -236,7 +260,11 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -38,7 +38,11 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -71,7 +75,11 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -104,7 +112,11 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -137,7 +149,11 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -170,7 +186,11 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -38,7 +38,11 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -57,7 +61,11 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -96,7 +104,11 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -136,7 +148,11 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -169,7 +185,11 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = {
rowSpan: 6,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -43,7 +43,11 @@ export const DEFAULT_WORKFLOW_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -44,7 +44,11 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -78,7 +82,11 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -44,7 +44,11 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -78,7 +82,11 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = {
rowSpan: 12,
columnSpan: 12,
},
configuration: null,
configuration: {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [],
},
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
@@ -1,28 +1,26 @@
import { type WidgetSizeConfig } from '@/page-layout/types/WidgetSizeConfig';
import { GraphType } from '~/generated-metadata/graphql';
import { WidgetConfigurationType } from '~/generated/graphql';
export const GRAPH_WIDGET_SIZES: Record<GraphType, WidgetSizeConfig> = {
[GraphType.AGGREGATE]: {
export const GRAPH_WIDGET_SIZES: Partial<
Record<WidgetConfigurationType, WidgetSizeConfig>
> = {
[WidgetConfigurationType.AGGREGATE_CHART]: {
default: { w: 2, h: 2 },
minimum: { w: 2, h: 2 },
},
[GraphType.GAUGE]: {
[WidgetConfigurationType.GAUGE_CHART]: {
default: { w: 3, h: 4 },
minimum: { w: 3, h: 4 },
},
[GraphType.PIE]: {
[WidgetConfigurationType.PIE_CHART]: {
default: { w: 4, h: 4 },
minimum: { w: 3, h: 4 },
},
[GraphType.VERTICAL_BAR]: {
[WidgetConfigurationType.BAR_CHART]: {
default: { w: 6, h: 6 },
minimum: { w: 4, h: 4 },
},
[GraphType.HORIZONTAL_BAR]: {
default: { w: 6, h: 6 },
minimum: { w: 4, h: 4 },
},
[GraphType.LINE]: {
[WidgetConfigurationType.LINE_CHART]: {
default: { w: 6, h: 10 },
minimum: { w: 4, h: 4 },
},
@@ -17,7 +17,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
}
configuration {
... on BarChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
primaryAxisGroupByFieldMetadataId
@@ -38,12 +38,13 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
description
filter
groupMode
layout
isCumulative
timezone
firstDayOfTheWeek
}
... on LineChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
primaryAxisGroupByFieldMetadataId
@@ -69,7 +70,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
firstDayOfTheWeek
}
... on PieChartConfiguration {
graphType
configurationType
groupByFieldMetadataId
aggregateFieldMetadataId
aggregateOperation
@@ -86,7 +87,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
firstDayOfTheWeek
}
... on AggregateChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
label
@@ -104,7 +105,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
}
}
... on GaugeChartConfiguration {
graphType
configurationType
aggregateFieldMetadataId
aggregateOperation
displayDataLabel
@@ -115,9 +116,11 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
firstDayOfTheWeek
}
... on IframeConfiguration {
configurationType
url
}
... on StandaloneRichTextConfiguration {
configurationType
body {
blocknote
markdown
@@ -5,11 +5,12 @@ import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetF
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { expect } from '@storybook/test';
import { act, renderHook } from '@testing-library/react';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { GraphType, WidgetType } from '~/generated-metadata/graphql';
import { PageLayoutType } from '~/generated/graphql';
import { WidgetType } from '~/generated-metadata/graphql';
import { PageLayoutType, WidgetConfigurationType } from '~/generated/graphql';
import {
PAGE_LAYOUT_TEST_INSTANCE_ID,
PageLayoutTestWrapper,
@@ -85,7 +86,10 @@ describe('useCreatePageLayoutGraphWidget', () => {
act(() => {
result.current.createWidget.createPageLayoutGraphWidget({
graphType: GraphType.VERTICAL_BAR,
fieldSelection: {
groupByFieldMetadataIdX: 'test-groupby-field-id',
aggregateFieldMetadataId: 'test-aggregate-field-id',
},
});
});
@@ -159,33 +163,34 @@ describe('useCreatePageLayoutGraphWidget', () => {
result.current.setActiveTabId('tab-1');
});
const graphTypes = [
GraphType.AGGREGATE,
GraphType.GAUGE,
GraphType.PIE,
GraphType.VERTICAL_BAR,
const widgetConfigurationTypes = [
WidgetConfigurationType.AGGREGATE_CHART,
WidgetConfigurationType.GAUGE_CHART,
WidgetConfigurationType.PIE_CHART,
WidgetConfigurationType.BAR_CHART,
];
const mockFieldSelections: Partial<
Record<GraphType, GraphWidgetFieldSelection>
Record<WidgetConfigurationType, GraphWidgetFieldSelection>
> = {
[GraphType.AGGREGATE]: {
[WidgetConfigurationType.AGGREGATE_CHART]: {
objectMetadataId: 'test-object-id',
aggregateFieldMetadataId: 'test-aggregate-field-id',
},
[GraphType.VERTICAL_BAR]: {
[WidgetConfigurationType.BAR_CHART]: {
objectMetadataId: 'test-object-id',
groupByFieldMetadataIdX: 'test-groupby-field-id',
aggregateFieldMetadataId: 'test-aggregate-field-id',
},
};
graphTypes.forEach((graphType) => {
widgetConfigurationTypes.forEach((widgetConfigurationType) => {
act(() => {
const fieldSelection =
mockFieldSelections[graphType as keyof typeof mockFieldSelections];
mockFieldSelections[
widgetConfigurationType as keyof typeof mockFieldSelections
];
result.current.createWidget.createPageLayoutGraphWidget({
graphType,
fieldSelection,
});
});
@@ -193,7 +198,7 @@ describe('useCreatePageLayoutGraphWidget', () => {
expect(result.current.allWidgets).toHaveLength(4);
graphTypes.forEach((graphType, index) => {
widgetConfigurationTypes.forEach((widgetConfigurationType, index) => {
const widget = result.current.allWidgets[index];
expect(widget.type).toBe(WidgetType.GRAPH);
expect(widget.pageLayoutTabId).toBe('tab-1');
@@ -202,7 +207,9 @@ describe('useCreatePageLayoutGraphWidget', () => {
isDefined(widget.configuration) &&
'graphType' in widget.configuration
) {
expect(widget.configuration.graphType).toBe(graphType);
expect(widget.configuration.configurationType).toBe(
widgetConfigurationType,
);
}
expect(widget.id).toBe('mock-uuid');
@@ -234,7 +241,10 @@ describe('useCreatePageLayoutGraphWidget', () => {
expect(() => {
result.current.createWidget.createPageLayoutGraphWidget({
graphType: GraphType.VERTICAL_BAR,
fieldSelection: {
groupByFieldMetadataIdX: 'test-groupby-field-id',
aggregateFieldMetadataId: 'test-aggregate-field-id',
},
});
}).toThrow('A tab must be selected to create a new graph widget');
});
@@ -1,11 +1,12 @@
import { act, renderHook } from '@testing-library/react';
import {
GraphOrderBy,
GraphType,
WidgetType,
} from '~/generated-metadata/graphql';
import { AggregateOperations, PageLayoutType } from '~/generated/graphql';
import { usePageLayoutDraftState } from '@/page-layout/hooks/usePageLayoutDraftState';
import { act, renderHook } from '@testing-library/react';
import { GraphOrderBy, WidgetType } from '~/generated-metadata/graphql';
import {
AggregateOperations,
BarChartLayout,
PageLayoutType,
WidgetConfigurationType,
} from '~/generated/graphql';
import {
PAGE_LAYOUT_TEST_INSTANCE_ID,
PageLayoutTestWrapper,
@@ -100,7 +101,8 @@ describe('usePageLayoutDraftState', () => {
type: WidgetType.GRAPH,
gridPosition: { row: 2, column: 2, rowSpan: 2, columnSpan: 2 },
configuration: {
graphType: GraphType.VERTICAL_BAR,
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
primaryAxisGroupByFieldMetadataId: 'createdAt',
@@ -1,3 +1,4 @@
import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType';
import { useDateTimeFormat } from '@/localization/hooks/useDateTimeFormat';
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
@@ -18,8 +19,11 @@ import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { v4 as uuidv4 } from 'uuid';
import { type GraphType } from '~/generated-metadata/graphql';
import { WidgetType } from '~/generated/graphql';
import {
BarChartLayout,
WidgetConfigurationType,
WidgetType,
} from '~/generated/graphql';
export const useCreatePageLayoutGraphWidget = (
pageLayoutIdFromProps?: string,
@@ -56,10 +60,8 @@ export const useCreatePageLayoutGraphWidget = (
const createPageLayoutGraphWidget = useRecoilCallback(
({ snapshot, set }) =>
({
graphType,
fieldSelection,
}: {
graphType: GraphType;
fieldSelection?: GraphWidgetFieldSelection;
}): PageLayoutWidget => {
const activeTabId = snapshot.getLoadable(activeTabIdState).getValue();
@@ -83,18 +85,39 @@ export const useCreatePageLayoutGraphWidget = (
.getValue();
const allWidgets = pageLayoutDraft.tabs.flatMap((tab) => tab.widgets);
const existingWidgetCount = allWidgets.filter(
(w) =>
w.type === WidgetType.GRAPH &&
w.configuration &&
'graphType' in w.configuration &&
w.configuration.graphType === graphType,
).length;
const title = getWidgetTitle(graphType, existingWidgetCount);
const existingWidgetCount = allWidgets.filter((widget) => {
if (widget.type !== WidgetType.GRAPH) {
return false;
}
if (
!isWidgetConfigurationOfType(
widget.configuration,
'BarChartConfiguration',
)
) {
return false;
}
return widget.configuration.layout === BarChartLayout.VERTICAL;
}).length;
const title = getWidgetTitle(
{
configurationType: WidgetConfigurationType.BAR_CHART,
layout: BarChartLayout.VERTICAL,
},
existingWidgetCount,
);
const widgetId = uuidv4();
const defaultSize = getWidgetSize(graphType, 'default');
const minimumSize = getWidgetSize(graphType, 'minimum');
const defaultSize = getWidgetSize(
WidgetConfigurationType.BAR_CHART,
'default',
);
const minimumSize = getWidgetSize(
WidgetConfigurationType.BAR_CHART,
'minimum',
);
const position = getDefaultWidgetPosition(
pageLayoutDraggedArea,
defaultSize,
@@ -105,7 +128,6 @@ export const useCreatePageLayoutGraphWidget = (
id: widgetId,
pageLayoutTabId: activeTabId,
title,
graphType,
gridPosition: {
row: position.y,
column: position.x,
@@ -36,6 +36,7 @@ export const useTemporaryFieldsConfiguration = (
return {
__typename: 'FieldsConfiguration',
configurationType: 'FIELDS',
sections: [
{
id: `${objectNameSingular}-section-general`,
@@ -1,6 +1,6 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { type TabLayouts } from '@/page-layout/types/tab-layouts';
import { type TabLayouts } from '@/page-layout/types/TabLayouts';
import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext';
export const pageLayoutCurrentLayoutsComponentState =
@@ -1,7 +1,7 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { PageLayoutType } from '~/generated/graphql';
import { type DraftPageLayout } from '@/page-layout/types/draft-page-layout';
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext';
export const pageLayoutDraftComponentState =
@@ -1,5 +1,8 @@
import { type WidgetConfigurationType } from '~/generated/graphql';
export type FieldConfiguration = {
__typename: 'FieldConfiguration';
configurationType: WidgetConfigurationType.FIELD;
fieldMetadataId: string;
layout: 'FIELD' | 'CARD' | 'VIEW';
};
@@ -15,5 +15,6 @@ export type FieldsConfigurationSection = {
export type FieldsConfiguration = {
__typename: 'FieldsConfiguration';
configurationType: 'FIELDS';
sections: FieldsConfigurationSection[];
};

Some files were not shown because too many files have changed in this diff Show More