[DASHBOARDS] Create display legend setting + animations (#16089)
## PR Description - Create display legend setting - Create pagination inside the legend - Animate the legend on enter/exit - Animate the transition between pages ## Video QA https://github.com/user-attachments/assets/a68a4ea3-195f-4399-88f7-f83bc1a39cc4
This commit is contained in:
@@ -321,6 +321,7 @@ export type BarChartConfiguration = {
|
||||
color?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
displayDataLabel?: Maybe<Scalars['Boolean']>;
|
||||
displayLegend?: Maybe<Scalars['Boolean']>;
|
||||
filter?: Maybe<Scalars['JSON']>;
|
||||
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
|
||||
graphType: GraphType;
|
||||
@@ -1671,6 +1672,7 @@ export type LineChartConfiguration = {
|
||||
color?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
displayDataLabel?: Maybe<Scalars['Boolean']>;
|
||||
displayLegend?: Maybe<Scalars['Boolean']>;
|
||||
filter?: Maybe<Scalars['JSON']>;
|
||||
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
|
||||
graphType: GraphType;
|
||||
@@ -3105,6 +3107,7 @@ export type PieChartConfiguration = {
|
||||
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;
|
||||
|
||||
@@ -321,6 +321,7 @@ export type BarChartConfiguration = {
|
||||
color?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
displayDataLabel?: Maybe<Scalars['Boolean']>;
|
||||
displayLegend?: Maybe<Scalars['Boolean']>;
|
||||
filter?: Maybe<Scalars['JSON']>;
|
||||
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
|
||||
graphType: GraphType;
|
||||
@@ -1647,6 +1648,7 @@ export type LineChartConfiguration = {
|
||||
color?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
displayDataLabel?: Maybe<Scalars['Boolean']>;
|
||||
displayLegend?: Maybe<Scalars['Boolean']>;
|
||||
filter?: Maybe<Scalars['JSON']>;
|
||||
firstDayOfTheWeek?: Maybe<Scalars['Int']>;
|
||||
graphType: GraphType;
|
||||
@@ -3039,6 +3041,7 @@ export type PieChartConfiguration = {
|
||||
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;
|
||||
@@ -4751,7 +4754,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, timezone?: string | null, firstDayOfTheWeek?: number | 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, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | 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, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: 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, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | 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', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | 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, 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, 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, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | null };
|
||||
|
||||
export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -4759,7 +4762,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, timezone?: string | null, firstDayOfTheWeek?: number | 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, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | 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, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: 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, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | 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', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | 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, 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, 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, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | null }> | null }> | null } };
|
||||
|
||||
export type OnDbEventSubscriptionVariables = Exact<{
|
||||
input: OnDbEventInput;
|
||||
@@ -5085,6 +5088,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
|
||||
omitNullValues
|
||||
axisNameDisplay
|
||||
displayDataLabel
|
||||
displayLegend
|
||||
rangeMin
|
||||
rangeMax
|
||||
color
|
||||
@@ -5109,6 +5113,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
|
||||
omitNullValues
|
||||
axisNameDisplay
|
||||
displayDataLabel
|
||||
displayLegend
|
||||
rangeMin
|
||||
rangeMax
|
||||
color
|
||||
@@ -5127,6 +5132,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
|
||||
dateGranularity
|
||||
orderBy
|
||||
displayDataLabel
|
||||
displayLegend
|
||||
color
|
||||
description
|
||||
filter
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import { OMIT_NULL_VALUES_SETTING } from '@/command-menu/pages/page-layout/const
|
||||
import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting';
|
||||
import { RANGE_MAX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMaxSetting';
|
||||
import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMinSetting';
|
||||
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_LINES_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedLineSettings';
|
||||
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
|
||||
@@ -48,6 +49,7 @@ export const LINE_CHART_SETTINGS: ChartSettingsGroup[] = [
|
||||
AXIS_NAME_SETTING,
|
||||
STACKED_LINES_SETTING,
|
||||
DATA_LABELS_SETTING,
|
||||
SHOW_LEGEND_SETTING,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import { DATE_GRANULARITY_SETTING } from '@/command-menu/pages/page-layout/const
|
||||
import { EACH_SLICE_REPRESENTS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/EachSliceRepresentsSetting';
|
||||
import { FILTER_SETTING } from '@/command-menu/pages/page-layout/constants/settings/FilterSetting';
|
||||
import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting';
|
||||
import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting';
|
||||
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
|
||||
|
||||
export const PIE_CHART_SETTINGS: ChartSettingsGroup[] = [
|
||||
@@ -22,6 +23,6 @@ export const PIE_CHART_SETTINGS: ChartSettingsGroup[] = [
|
||||
},
|
||||
{
|
||||
heading: 'Style',
|
||||
items: [COLORS_SETTING, DATA_LABELS_SETTING],
|
||||
items: [COLORS_SETTING, DATA_LABELS_SETTING, SHOW_LEGEND_SETTING],
|
||||
},
|
||||
];
|
||||
|
||||
+1
@@ -22,4 +22,5 @@ export const CHART_CONFIGURATION_SETTING_LABELS = {
|
||||
DATE_GRANULARITY_X: msg`Date granularity`,
|
||||
DATE_GRANULARITY_Y: msg`Date granularity`,
|
||||
DATE_GRANULARITY: msg`Date granularity`,
|
||||
SHOW_LEGEND: msg`Legend`,
|
||||
};
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels';
|
||||
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 { IconList } from 'twenty-ui/display';
|
||||
|
||||
export const SHOW_LEGEND_SETTING: ChartSettingsItem = {
|
||||
isBoolean: true,
|
||||
Icon: IconList,
|
||||
label: CHART_CONFIGURATION_SETTING_LABELS.SHOW_LEGEND,
|
||||
id: CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND,
|
||||
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.GROUP_BY],
|
||||
};
|
||||
+2
@@ -235,6 +235,8 @@ export const useChartSettingsValues = ({
|
||||
return isPieChart && isDefined(configuration.dateGranularity)
|
||||
? getDateGranularityLabel(configuration.dateGranularity)
|
||||
: undefined;
|
||||
case CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND:
|
||||
return isPieChart ? (configuration.displayLegend ?? true) : true;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
+2
@@ -21,6 +21,7 @@ export enum CHART_CONFIGURATION_SETTING_IDS {
|
||||
DATE_GRANULARITY_X = 'DATE_GRANULARITY_X',
|
||||
DATE_GRANULARITY_Y = 'DATE_GRANULARITY_Y',
|
||||
DATE_GRANULARITY = 'DATE_GRANULARITY',
|
||||
SHOW_LEGEND = 'SHOW_LEGEND',
|
||||
}
|
||||
|
||||
export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = {
|
||||
@@ -35,4 +36,5 @@ export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = {
|
||||
[CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_Y]:
|
||||
'secondaryAxisGroupByDateGranularity',
|
||||
[CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY]: 'dateGranularity',
|
||||
[CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND]: 'displayLegend',
|
||||
} as const;
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import { OMIT_NULL_VALUES_SETTING } from '@/command-menu/pages/page-layout/const
|
||||
import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting';
|
||||
import { RANGE_MAX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMaxSetting';
|
||||
import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMinSetting';
|
||||
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';
|
||||
@@ -143,6 +144,7 @@ describe('getBarChartSettings', () => {
|
||||
AXIS_NAME_SETTING,
|
||||
STACKED_BARS_SETTING,
|
||||
DATA_LABELS_SETTING,
|
||||
SHOW_LEGEND_SETTING,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import { OMIT_NULL_VALUES_SETTING } from '@/command-menu/pages/page-layout/const
|
||||
import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting';
|
||||
import { RANGE_MAX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMaxSetting';
|
||||
import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMinSetting';
|
||||
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 { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
|
||||
@@ -65,6 +66,7 @@ export const getBarChartSettings = (
|
||||
AXIS_NAME_SETTING,
|
||||
STACKED_BARS_SETTING,
|
||||
DATA_LABELS_SETTING,
|
||||
SHOW_LEGEND_SETTING,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
+6
@@ -74,6 +74,12 @@ export const shouldHideChartSetting = (
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.id === CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND) {
|
||||
if (configuration.__typename === 'PieChartConfiguration') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+3
@@ -31,6 +31,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
|
||||
omitNullValues
|
||||
axisNameDisplay
|
||||
displayDataLabel
|
||||
displayLegend
|
||||
rangeMin
|
||||
rangeMax
|
||||
color
|
||||
@@ -55,6 +56,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
|
||||
omitNullValues
|
||||
axisNameDisplay
|
||||
displayDataLabel
|
||||
displayLegend
|
||||
rangeMin
|
||||
rangeMax
|
||||
color
|
||||
@@ -73,6 +75,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
|
||||
dateGranularity
|
||||
orderBy
|
||||
displayDataLabel
|
||||
displayLegend
|
||||
color
|
||||
description
|
||||
filter
|
||||
|
||||
+217
-31
@@ -1,5 +1,18 @@
|
||||
import { CHART_LEGEND_ITEM_THRESHOLD } from '@/page-layout/widgets/graph/constants/ChartLegendItemThreshold';
|
||||
import { GraphWidgetLegendDot } from '@/page-layout/widgets/graph/components/GraphWidgetLegendDot';
|
||||
import { LEGEND_ITEM_ESTIMATED_WIDTH } from '@/page-layout/widgets/graph/constants/LegendItemEstimatedWidth.constant';
|
||||
import { LEGEND_LABEL_MAX_WIDTH } from '@/page-layout/widgets/graph/constants/LegendLabelMaxWidth.constant';
|
||||
import { LEGEND_PAGINATION_CONTROLS_WIDTH } from '@/page-layout/widgets/graph/constants/LegendPaginationControlsWidth.constant';
|
||||
import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDimensionEffect';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useRef, useState } from 'react';
|
||||
import {
|
||||
IconChevronLeft,
|
||||
IconChevronRight,
|
||||
OverflowingTextWithTooltip,
|
||||
} from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
|
||||
export type GraphWidgetLegendItem = {
|
||||
id: string;
|
||||
@@ -12,59 +25,232 @@ type GraphWidgetLegendProps = {
|
||||
show?: boolean;
|
||||
};
|
||||
|
||||
const StyledLegendContainer = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
justify-content: center;
|
||||
padding-top: ${({ theme }) => theme.spacing(3)};
|
||||
type AnimationDirection = 'forward' | 'backward';
|
||||
|
||||
const StyledAnimationClipContainer = styled.div`
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const StyledLegendItem = styled.div`
|
||||
const StyledLegendMotionWrapper = styled(motion.div)`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledItemsWrapper = styled(motion.div)<{ centered?: boolean }>`
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
flex-wrap: nowrap;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
justify-content: ${({ centered }) => (centered ? 'center' : 'flex-start')};
|
||||
`;
|
||||
|
||||
const StyledLegendContainer = styled.div<{ needsPagination: boolean }>`
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
justify-content: ${({ needsPagination }) =>
|
||||
needsPagination ? 'flex-start' : 'center'};
|
||||
padding-top: ${({ theme }) => theme.spacing(3)};
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const StyledLegendItem = styled.div<{ canShrink?: boolean }>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
flex-shrink: ${({ canShrink }) => (canShrink ? 1 : 0)};
|
||||
min-width: 0;
|
||||
`;
|
||||
|
||||
const StyledLegendLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
const StyledLegendLabel = styled.div<{ fixedWidth?: boolean }>`
|
||||
color: ${({ theme }) => theme.font.color.secondary};
|
||||
${({ fixedWidth }) => fixedWidth && `width: ${LEGEND_LABEL_MAX_WIDTH}px;`}
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledDot = styled.div<{ color: string }>`
|
||||
background: ${({ color }) => color};
|
||||
border-radius: 50%;
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
const StyledPaginationContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
gap: ${({ theme }) => theme.spacing(0.5)};
|
||||
`;
|
||||
|
||||
const StyledPaginationIndicator = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
`;
|
||||
|
||||
const legendEnterExitVariants = {
|
||||
hidden: {
|
||||
y: 10,
|
||||
opacity: 0,
|
||||
},
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
},
|
||||
exit: {
|
||||
y: 10,
|
||||
opacity: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export const GraphWidgetLegend = ({
|
||||
items,
|
||||
show = true,
|
||||
}: GraphWidgetLegendProps) => {
|
||||
const areThereTooManyItems = items.length > CHART_LEGEND_ITEM_THRESHOLD;
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isItASingleItem = items.length === 1;
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
|
||||
const thereAreNoItems = items.length === 0;
|
||||
const [containerWidth, setContainerWidth] = useState(0);
|
||||
|
||||
const shouldShowLegend =
|
||||
show && !areThereTooManyItems && !isItASingleItem && !thereAreNoItems;
|
||||
const [animationDirection, setAnimationDirection] =
|
||||
useState<AnimationDirection>('forward');
|
||||
|
||||
if (!shouldShowLegend) {
|
||||
return null;
|
||||
}
|
||||
const theme = useTheme();
|
||||
|
||||
const shouldShowLegend = show && items.length > 1;
|
||||
|
||||
const availableWidth = containerWidth - LEGEND_PAGINATION_CONTROLS_WIDTH;
|
||||
|
||||
const itemsPerPage = Math.max(
|
||||
1,
|
||||
Math.floor(availableWidth / LEGEND_ITEM_ESTIMATED_WIDTH),
|
||||
);
|
||||
|
||||
const needsPagination = items.length > itemsPerPage;
|
||||
const totalPages = Math.ceil(items.length / itemsPerPage);
|
||||
const safeCurrentPage = Math.min(currentPage, Math.max(0, totalPages - 1));
|
||||
|
||||
const startIndex = safeCurrentPage * itemsPerPage;
|
||||
const visibleItems = needsPagination
|
||||
? items.slice(startIndex, startIndex + itemsPerPage)
|
||||
: items;
|
||||
|
||||
const handlePreviousPage = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
setAnimationDirection('backward');
|
||||
setCurrentPage((prevPage) => Math.max(0, prevPage - 1));
|
||||
};
|
||||
|
||||
const handleNextPage = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
setAnimationDirection('forward');
|
||||
setCurrentPage((prevPage) => Math.min(totalPages - 1, prevPage + 1));
|
||||
};
|
||||
|
||||
const slideOffset = availableWidth;
|
||||
|
||||
const variants = {
|
||||
enter: (direction: AnimationDirection) => ({
|
||||
x: direction === 'forward' ? slideOffset : -slideOffset,
|
||||
}),
|
||||
center: {
|
||||
x: 0,
|
||||
},
|
||||
exit: (direction: AnimationDirection) => ({
|
||||
x: direction === 'forward' ? -slideOffset : slideOffset,
|
||||
}),
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledLegendContainer>
|
||||
{items.map((item) => (
|
||||
<StyledLegendItem key={item.id}>
|
||||
<StyledDot color={item.color} />
|
||||
<StyledLegendLabel>{item.label}</StyledLegendLabel>
|
||||
</StyledLegendItem>
|
||||
))}
|
||||
</StyledLegendContainer>
|
||||
<AnimatePresence mode="popLayout" initial={false}>
|
||||
{shouldShowLegend && (
|
||||
<StyledLegendMotionWrapper
|
||||
variants={legendEnterExitVariants}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
transition={{
|
||||
duration: theme.animation.duration.normal,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<StyledLegendContainer
|
||||
ref={containerRef}
|
||||
needsPagination={needsPagination}
|
||||
>
|
||||
<NodeDimensionEffect
|
||||
elementRef={containerRef}
|
||||
onDimensionChange={({ width }) => {
|
||||
const newItemsPerPage = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
(width - LEGEND_PAGINATION_CONTROLS_WIDTH) /
|
||||
LEGEND_ITEM_ESTIMATED_WIDTH,
|
||||
),
|
||||
);
|
||||
|
||||
if (newItemsPerPage !== itemsPerPage) {
|
||||
setCurrentPage(0);
|
||||
}
|
||||
|
||||
setContainerWidth(width);
|
||||
}}
|
||||
/>
|
||||
{needsPagination && (
|
||||
<StyledPaginationContainer>
|
||||
<LightIconButton
|
||||
onClick={handlePreviousPage}
|
||||
disabled={safeCurrentPage === 0}
|
||||
Icon={IconChevronLeft}
|
||||
accent="tertiary"
|
||||
/>
|
||||
<StyledPaginationIndicator>
|
||||
{safeCurrentPage + 1}/{totalPages}
|
||||
</StyledPaginationIndicator>
|
||||
<LightIconButton
|
||||
onClick={handleNextPage}
|
||||
disabled={safeCurrentPage === totalPages - 1}
|
||||
Icon={IconChevronRight}
|
||||
/>
|
||||
</StyledPaginationContainer>
|
||||
)}
|
||||
<StyledAnimationClipContainer>
|
||||
<AnimatePresence
|
||||
mode="popLayout"
|
||||
custom={animationDirection}
|
||||
initial={false}
|
||||
>
|
||||
<StyledItemsWrapper
|
||||
key={safeCurrentPage}
|
||||
custom={animationDirection}
|
||||
variants={variants}
|
||||
initial="enter"
|
||||
animate="center"
|
||||
exit="exit"
|
||||
transition={{
|
||||
duration: theme.animation.duration.normal,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
centered={!needsPagination}
|
||||
>
|
||||
{visibleItems.map((item) => (
|
||||
<StyledLegendItem
|
||||
key={item.id}
|
||||
canShrink={!needsPagination}
|
||||
>
|
||||
<GraphWidgetLegendDot color={item.color} />
|
||||
<StyledLegendLabel fixedWidth={needsPagination}>
|
||||
<OverflowingTextWithTooltip text={item.label} />
|
||||
</StyledLegendLabel>
|
||||
</StyledLegendItem>
|
||||
))}
|
||||
</StyledItemsWrapper>
|
||||
</AnimatePresence>
|
||||
</StyledAnimationClipContainer>
|
||||
</StyledLegendContainer>
|
||||
</StyledLegendMotionWrapper>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
type GraphWidgetLegendDotProps = {
|
||||
color: string;
|
||||
};
|
||||
|
||||
const StyledDot = styled.div<{ color: string }>`
|
||||
background: ${({ color }) => color};
|
||||
border-radius: 2px;
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
export const GraphWidgetLegendDot = ({ color }: GraphWidgetLegendDotProps) => {
|
||||
return <StyledDot color={color} />;
|
||||
};
|
||||
+3
-10
@@ -1,12 +1,13 @@
|
||||
import { GRAPH_TOOLTIP_MAX_WIDTH_PX } from '@/page-layout/widgets/graph/components/constants/GraphTooltipMaxWidthPx';
|
||||
import { GRAPH_TOOLTIP_MIN_WIDTH_PX } from '@/page-layout/widgets/graph/components/constants/GraphTooltipMinWidthPx';
|
||||
import { GRAPH_TOOLTIP_SCROLL_MAX_HEIGHT_PX } from '@/page-layout/widgets/graph/components/constants/GraphTooltipScrollMaxHeightPx';
|
||||
import { GraphWidgetLegendDot } from '@/page-layout/widgets/graph/components/GraphWidgetLegendDot';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { IconArrowUpRight } from 'twenty-ui/display';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconArrowUpRight } from 'twenty-ui/display';
|
||||
|
||||
const StyledTooltip = styled.div`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
@@ -43,14 +44,6 @@ const StyledTooltipRowContainer = styled.div`
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
const StyledDot = styled.div<{ color: string }>`
|
||||
background: ${({ color }) => color};
|
||||
border-radius: 50%;
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
const StyledTooltipLink = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
@@ -168,7 +161,7 @@ export const GraphWidgetTooltip = ({
|
||||
shouldHighlight && highlightedKey === item.key;
|
||||
return (
|
||||
<StyledTooltipRow key={item.key}>
|
||||
<StyledDot color={item.dotColor} />
|
||||
<GraphWidgetLegendDot color={item.dotColor} />
|
||||
<StyledTooltipRowRightContent>
|
||||
<StyledTooltipLabel isHighlighted={isHighlighted}>
|
||||
{item.label}
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
export const CHART_LEGEND_ITEM_THRESHOLD = 10;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// Estimated width of a legend item in pixels (dot + gap + label + container gap)
|
||||
export const LEGEND_ITEM_ESTIMATED_WIDTH = 100;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// Max width of a legend label before truncation
|
||||
export const LEGEND_LABEL_MAX_WIDTH = 80;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// Width of pagination controls (prev button + indicator + next button)
|
||||
export const LEGEND_PAGINATION_CONTROLS_WIDTH = 70;
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
|
||||
import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader';
|
||||
import { GraphWidgetChartHasTooManyGroupsEffect } from '@/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect';
|
||||
import { useGraphBarChartWidgetData } from '@/page-layout/widgets/graph/graphWidgetBarChart/hooks/useGraphBarChartWidgetData';
|
||||
@@ -5,7 +6,6 @@ import { type BarChartDataItem } from '@/page-layout/widgets/graph/graphWidgetBa
|
||||
import { getEffectiveGroupMode } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/getEffectiveGroupMode';
|
||||
import { buildChartDrilldownQueryParams } from '@/page-layout/widgets/graph/utils/buildChartDrilldownQueryParams';
|
||||
import { generateChartAggregateFilterKey } from '@/page-layout/widgets/graph/utils/generateChartAggregateFilterKey';
|
||||
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { type ComputedDatum } from '@nivo/bar';
|
||||
@@ -40,6 +40,7 @@ export const GraphWidgetBarChartRenderer = ({
|
||||
xAxisLabel,
|
||||
yAxisLabel,
|
||||
showDataLabels,
|
||||
showLegend,
|
||||
layout,
|
||||
loading,
|
||||
hasTooManyGroups,
|
||||
@@ -116,6 +117,7 @@ export const GraphWidgetBarChartRenderer = ({
|
||||
xAxisLabel={xAxisLabel}
|
||||
yAxisLabel={yAxisLabel}
|
||||
showValues={showDataLabels}
|
||||
showLegend={showLegend}
|
||||
layout={layout}
|
||||
groupMode={groupMode}
|
||||
id={widget.id}
|
||||
|
||||
+3
-3
@@ -17,9 +17,9 @@ export const useBarChartTheme = () => {
|
||||
},
|
||||
legend: {
|
||||
text: {
|
||||
fill: theme.font.color.secondary,
|
||||
fontSize: 12,
|
||||
fontWeight: theme.font.weight.regular,
|
||||
fill: theme.font.color.primary,
|
||||
fontSize: theme.font.size.sm,
|
||||
fontWeight: theme.font.weight.medium,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ type UseGraphBarChartWidgetDataResult = {
|
||||
xAxisLabel?: string;
|
||||
yAxisLabel?: string;
|
||||
showDataLabels: boolean;
|
||||
showLegend: boolean;
|
||||
layout?: BarChartLayout;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
|
||||
+4
@@ -37,6 +37,7 @@ type TransformGroupByDataToBarChartDataResult = {
|
||||
xAxisLabel?: string;
|
||||
yAxisLabel?: string;
|
||||
showDataLabels: boolean;
|
||||
showLegend: boolean;
|
||||
layout?: BarChartLayout;
|
||||
hasTooManyGroups: boolean;
|
||||
formattedToRawLookup: Map<string, RawDimensionValue>;
|
||||
@@ -50,6 +51,7 @@ const EMPTY_BAR_CHART_RESULT: TransformGroupByDataToBarChartDataResult = {
|
||||
xAxisLabel: undefined,
|
||||
yAxisLabel: undefined,
|
||||
showDataLabels: false,
|
||||
showLegend: true,
|
||||
layout: BarChartLayout.VERTICAL,
|
||||
hasTooManyGroups: false,
|
||||
formattedToRawLookup: new Map(),
|
||||
@@ -146,6 +148,7 @@ export const transformGroupByDataToBarChartData = ({
|
||||
: undefined;
|
||||
|
||||
const showDataLabels = configuration.displayDataLabel ?? false;
|
||||
const showLegend = configuration.displayLegend ?? true;
|
||||
|
||||
const isDateField =
|
||||
groupByFieldX.type === FieldMetadataType.DATE ||
|
||||
@@ -199,6 +202,7 @@ export const transformGroupByDataToBarChartData = ({
|
||||
xAxisLabel,
|
||||
yAxisLabel,
|
||||
showDataLabels,
|
||||
showLegend,
|
||||
layout,
|
||||
hasTooManyGroups: baseResult.hasTooManyGroups || dateRangeWasTruncated,
|
||||
formattedToRawLookup: baseResult.formattedToRawLookup,
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
|
||||
import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader';
|
||||
import { GraphWidgetChartHasTooManyGroupsEffect } from '@/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect';
|
||||
import { LINE_CHART_IS_STACKED_DEFAULT } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartIsStackedDefault';
|
||||
@@ -5,7 +6,6 @@ import { useGraphLineChartWidgetData } from '@/page-layout/widgets/graph/graphWi
|
||||
import { type LineChartDataPoint } from '@/page-layout/widgets/graph/graphWidgetLineChart/types/LineChartDataPoint';
|
||||
import { buildChartDrilldownQueryParams } from '@/page-layout/widgets/graph/utils/buildChartDrilldownQueryParams';
|
||||
import { generateChartAggregateFilterKey } from '@/page-layout/widgets/graph/utils/generateChartAggregateFilterKey';
|
||||
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { type LineSeries, type Point } from '@nivo/line';
|
||||
@@ -37,6 +37,7 @@ export const GraphWidgetLineChartRenderer = ({
|
||||
xAxisLabel,
|
||||
yAxisLabel,
|
||||
showDataLabels,
|
||||
showLegend,
|
||||
hasTooManyGroups,
|
||||
loading,
|
||||
formattedToRawLookup,
|
||||
@@ -113,6 +114,7 @@ export const GraphWidgetLineChartRenderer = ({
|
||||
xAxisLabel={xAxisLabel}
|
||||
yAxisLabel={yAxisLabel}
|
||||
enablePointLabel={showDataLabels}
|
||||
showLegend={showLegend}
|
||||
rangeMin={configuration.rangeMin ?? undefined}
|
||||
rangeMax={configuration.rangeMax ?? undefined}
|
||||
omitNullValues={configuration.omitNullValues ?? false}
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ type UseGraphLineChartWidgetDataResult = {
|
||||
xAxisLabel?: string;
|
||||
yAxisLabel?: string;
|
||||
showDataLabels: boolean;
|
||||
showLegend: boolean;
|
||||
hasTooManyGroups: boolean;
|
||||
formattedToRawLookup: Map<string, RawDimensionValue>;
|
||||
loading: boolean;
|
||||
|
||||
+3
-3
@@ -23,9 +23,9 @@ export const useLineChartTheme = () => {
|
||||
},
|
||||
legend: {
|
||||
text: {
|
||||
fill: theme.font.color.secondary,
|
||||
fontSize: 12,
|
||||
fontWeight: theme.font.weight.regular,
|
||||
fill: theme.font.color.primary,
|
||||
fontSize: theme.font.size.sm,
|
||||
fontWeight: theme.font.weight.medium,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+8
@@ -152,6 +152,14 @@ export const GraphWidgetPieChart = ({
|
||||
arcLinkLabelsStraightLength={10}
|
||||
arcLinkLabelsTextColor={theme.font.color.light}
|
||||
arcLinkLabelsColor={theme.font.color.extraLight}
|
||||
theme={{
|
||||
labels: {
|
||||
text: {
|
||||
fontSize: theme.font.size.sm,
|
||||
fontWeight: theme.font.weight.medium,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</StyledPieChartWrapper>
|
||||
</GraphWidgetChartContainer>
|
||||
|
||||
+3
-1
@@ -32,8 +32,9 @@ export const GraphWidgetPieChartRenderer = ({
|
||||
loading,
|
||||
hasTooManyGroups,
|
||||
objectMetadataItem,
|
||||
formattedToRawLookup,
|
||||
showLegend,
|
||||
showDataLabels,
|
||||
formattedToRawLookup,
|
||||
} = useGraphPieChartWidgetData({
|
||||
objectMetadataItemId: widget.objectMetadataId,
|
||||
configuration: widget.configuration as PieChartConfiguration,
|
||||
@@ -84,6 +85,7 @@ export const GraphWidgetPieChartRenderer = ({
|
||||
<GraphWidgetPieChart
|
||||
data={data}
|
||||
id={widget.id}
|
||||
showLegend={showLegend}
|
||||
displayType="shortNumber"
|
||||
onSliceClick={handleSliceClick}
|
||||
showDataLabels={showDataLabels}
|
||||
|
||||
+2
-3
@@ -1,5 +1,6 @@
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { EXTRA_ITEM_TO_DETECT_TOO_MANY_GROUPS } from '@/page-layout/widgets/graph/constants/ExtraItemToDetectTooManyGroups.constant';
|
||||
import { PIE_CHART_MAXIMUM_NUMBER_OF_SLICES } from '@/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMaximumNumberOfSlices.constant';
|
||||
import { type PieChartDataItem } from '@/page-layout/widgets/graph/graphWidgetPieChart/types/PieChartDataItem';
|
||||
import { transformGroupByDataToPieChartData } from '@/page-layout/widgets/graph/graphWidgetPieChart/utils/transformGroupByDataToPieChartData';
|
||||
@@ -15,6 +16,7 @@ type UseGraphPieChartWidgetDataProps = {
|
||||
|
||||
type UseGraphPieChartWidgetDataResult = {
|
||||
data: PieChartDataItem[];
|
||||
showLegend: boolean;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
hasTooManyGroups: boolean;
|
||||
@@ -23,9 +25,6 @@ type UseGraphPieChartWidgetDataResult = {
|
||||
showDataLabels: boolean;
|
||||
};
|
||||
|
||||
// TODO: Remove this once backend returns total group count
|
||||
const EXTRA_ITEM_TO_DETECT_TOO_MANY_GROUPS = 1;
|
||||
|
||||
export const useGraphPieChartWidgetData = ({
|
||||
objectMetadataItemId,
|
||||
configuration,
|
||||
|
||||
+5
@@ -22,12 +22,14 @@ type TransformGroupByDataToPieChartDataParams = {
|
||||
|
||||
type TransformGroupByDataToPieChartDataResult = {
|
||||
data: PieChartDataItem[];
|
||||
showLegend: boolean;
|
||||
hasTooManyGroups: boolean;
|
||||
formattedToRawLookup: Map<string, RawDimensionValue>;
|
||||
};
|
||||
|
||||
const EMPTY_PIE_CHART_RESULT: TransformGroupByDataToPieChartDataResult = {
|
||||
data: [],
|
||||
showLegend: true,
|
||||
hasTooManyGroups: false,
|
||||
formattedToRawLookup: new Map(),
|
||||
};
|
||||
@@ -99,8 +101,11 @@ export const transformGroupByDataToPieChartData = ({
|
||||
};
|
||||
});
|
||||
|
||||
const showLegend = configuration.displayLegend ?? true;
|
||||
|
||||
return {
|
||||
data,
|
||||
showLegend,
|
||||
hasTooManyGroups: rawResults.length > PIE_CHART_MAXIMUM_NUMBER_OF_SLICES,
|
||||
formattedToRawLookup,
|
||||
};
|
||||
|
||||
+4
@@ -27,6 +27,7 @@ type TransformGroupByDataToLineChartDataResult = {
|
||||
xAxisLabel?: string;
|
||||
yAxisLabel?: string;
|
||||
showDataLabels: boolean;
|
||||
showLegend: boolean;
|
||||
hasTooManyGroups: boolean;
|
||||
formattedToRawLookup: Map<string, RawDimensionValue>;
|
||||
};
|
||||
@@ -36,6 +37,7 @@ const EMPTY_LINE_CHART_RESULT: TransformGroupByDataToLineChartDataResult = {
|
||||
xAxisLabel: undefined,
|
||||
yAxisLabel: undefined,
|
||||
showDataLabels: false,
|
||||
showLegend: true,
|
||||
hasTooManyGroups: false,
|
||||
formattedToRawLookup: new Map(),
|
||||
};
|
||||
@@ -113,6 +115,7 @@ export const transformGroupByDataToLineChartData = ({
|
||||
: undefined;
|
||||
|
||||
const showDataLabels = configuration.displayDataLabel ?? false;
|
||||
const showLegend = configuration.displayLegend ?? true;
|
||||
|
||||
const baseResult = isDefined(groupByFieldY)
|
||||
? transformTwoDimensionalGroupByToLineChartData({
|
||||
@@ -140,6 +143,7 @@ export const transformGroupByDataToLineChartData = ({
|
||||
xAxisLabel,
|
||||
yAxisLabel,
|
||||
showDataLabels,
|
||||
showLegend,
|
||||
formattedToRawLookup: baseResult.formattedToRawLookup,
|
||||
};
|
||||
};
|
||||
|
||||
+5
@@ -108,6 +108,11 @@ export class BarChartConfigurationDTO {
|
||||
@IsOptional()
|
||||
displayDataLabel?: boolean;
|
||||
|
||||
@Field(() => Boolean, { nullable: true, defaultValue: true })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
displayLegend?: boolean;
|
||||
|
||||
@Field(() => Number, { nullable: true })
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
|
||||
+5
@@ -109,6 +109,11 @@ export class LineChartConfigurationDTO {
|
||||
@IsOptional()
|
||||
displayDataLabel?: boolean;
|
||||
|
||||
@Field(() => Boolean, { nullable: true, defaultValue: true })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
displayLegend?: boolean;
|
||||
|
||||
@Field(() => Number, { nullable: true })
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
|
||||
+5
@@ -71,6 +71,11 @@ export class PieChartConfigurationDTO {
|
||||
@IsOptional()
|
||||
displayDataLabel?: boolean;
|
||||
|
||||
@Field(() => Boolean, { nullable: true, defaultValue: true })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
displayLegend?: boolean;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
|
||||
Reference in New Issue
Block a user