Convert number chart to aggregate chart allowing date aggregates (#15294)

- Convert number chart to aggregate chart 
- Allow date aggregates on all charts
- Only allow `EARLIEST` and `LATEST` on Aggregate chart and Gauge chart
- Various design fixes


https://github.com/user-attachments/assets/b5a2239d-7b11-48b5-93e6-98ceffae5cab
This commit is contained in:
Raphaël Bosi
2025-10-23 18:48:42 +02:00
committed by GitHub
parent 6f45c47435
commit f301f07e43
45 changed files with 205 additions and 151 deletions
@@ -126,6 +126,18 @@ export type AgentIdInput = {
id: Scalars['UUID'];
};
export type AggregateChartConfiguration = {
__typename?: 'AggregateChartConfiguration';
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
};
export enum AggregateOperations {
AVG = 'AVG',
COUNT = 'COUNT',
@@ -1453,10 +1465,10 @@ export enum GraphOrderBy {
/** Type of graph widget */
export enum GraphType {
AGGREGATE = 'AGGREGATE',
GAUGE = 'GAUGE',
HORIZONTAL_BAR = 'HORIZONTAL_BAR',
LINE = 'LINE',
NUMBER = 'NUMBER',
PIE = 'PIE',
VERTICAL_BAR = 'VERTICAL_BAR'
}
@@ -2789,18 +2801,6 @@ export type NativeModelCapabilities = {
webSearch?: Maybe<Scalars['Boolean']>;
};
export type NumberChartConfiguration = {
__typename?: 'NumberChartConfiguration';
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
};
export type Object = {
__typename?: 'Object';
applicationId?: Maybe<Scalars['UUID']>;
@@ -4540,7 +4540,7 @@ export type Webhook = {
workspaceId: Scalars['UUID'];
};
export type WidgetConfiguration = BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NumberChartConfiguration | PieChartConfiguration;
export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | PieChartConfiguration;
export enum WidgetType {
CALENDAR = 'CALENDAR',
+17 -17
View File
@@ -126,6 +126,18 @@ export type AgentIdInput = {
id: Scalars['UUID'];
};
export type AggregateChartConfiguration = {
__typename?: 'AggregateChartConfiguration';
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
};
export enum AggregateOperations {
AVG = 'AVG',
COUNT = 'COUNT',
@@ -1410,10 +1422,10 @@ export enum GraphOrderBy {
/** Type of graph widget */
export enum GraphType {
AGGREGATE = 'AGGREGATE',
GAUGE = 'GAUGE',
HORIZONTAL_BAR = 'HORIZONTAL_BAR',
LINE = 'LINE',
NUMBER = 'NUMBER',
PIE = 'PIE',
VERTICAL_BAR = 'VERTICAL_BAR'
}
@@ -2700,18 +2712,6 @@ export type NativeModelCapabilities = {
webSearch?: Maybe<Scalars['Boolean']>;
};
export type NumberChartConfiguration = {
__typename?: 'NumberChartConfiguration';
aggregateFieldMetadataId: Scalars['UUID'];
aggregateOperation: AggregateOperations;
description?: Maybe<Scalars['String']>;
displayDataLabel?: Maybe<Scalars['Boolean']>;
filter?: Maybe<Scalars['JSON']>;
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
};
export type Object = {
__typename?: 'Object';
applicationId?: Maybe<Scalars['UUID']>;
@@ -4368,7 +4368,7 @@ export type Webhook = {
workspaceId: Scalars['UUID'];
};
export type WidgetConfiguration = BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NumberChartConfiguration | PieChartConfiguration;
export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | PieChartConfiguration;
export enum WidgetType {
CALENDAR = 'CALENDAR',
@@ -4627,7 +4627,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?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'NumberChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | 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, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | null };
export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{
id: Scalars['String'];
@@ -4635,7 +4635,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?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'NumberChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | 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, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | 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 } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | null }> | null }> | null } };
export type OnDbEventSubscriptionVariables = Exact<{
input: OnDbEventInput;
@@ -4983,7 +4983,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql`
description
filter
}
... on NumberChartConfiguration {
... on AggregateChartConfiguration {
graphType
aggregateFieldMetadataId
aggregateOperation
@@ -16,6 +16,7 @@ import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { isChartSettingDisabled } from '@/command-menu/pages/page-layout/utils/isChartSettingDisabled';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { GRAPH_MAXIMUM_NUMBER_OF_GROUPS } from '@/page-layout/widgets/graph/constants/GraphMaximumNumberOfGroups.constant';
import { hasWidgetTooManyGroupsComponentState } from '@/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
@@ -23,9 +24,14 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import { SidePanelInformationBanner } from 'twenty-ui/display';
import { GraphType, type PageLayoutWidget } from '~/generated/graphql';
import {
AggregateOperations,
GraphType,
type PageLayoutWidget,
} from '~/generated/graphql';
const StyledSidePanelInformationBanner = styled(SidePanelInformationBanner)`
margin-top: ${({ theme }) => theme.spacing(2)};
@@ -41,6 +47,7 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
const { setSelectedItemId } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
const { objectMetadataItems } = useObjectMetadataItems();
if (widget.configuration?.__typename === 'IframeConfiguration') {
throw new Error(t`IframeConfiguration is not supported`);
@@ -69,11 +76,37 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
useRecoilComponentState(hasWidgetTooManyGroupsComponentState);
const handleGraphTypeChange = (graphType: GraphType) => {
const configToUpdate: Record<string, any> = {
__typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType],
graphType,
};
if (graphType !== GraphType.AGGREGATE && graphType !== GraphType.GAUGE) {
const currentAggregateFieldMetadataId =
configuration.aggregateFieldMetadataId;
const objectMetadataItem = objectMetadataItems.find(
(item) => item.id === widget.objectMetadataId,
);
if (isDefined(objectMetadataItem)) {
const aggregateField = objectMetadataItem.fields.find(
(field) => field.id === currentAggregateFieldMetadataId,
);
if (
isDefined(aggregateField) &&
isFieldMetadataDateKind(aggregateField.type) &&
(configuration.aggregateOperation === AggregateOperations.MIN ||
configuration.aggregateOperation === AggregateOperations.MAX)
) {
configToUpdate.aggregateOperation = AggregateOperations.COUNT;
}
}
}
updateCurrentWidgetConfig({
configToUpdate: {
__typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType],
graphType,
},
configToUpdate,
});
updateCommandMenuPageInfo({
@@ -8,7 +8,7 @@ import { MenuPicker } from 'twenty-ui/navigation';
const graphTypeOptions = [
GraphType.VERTICAL_BAR,
GraphType.HORIZONTAL_BAR,
GraphType.NUMBER,
GraphType.AGGREGATE,
GraphType.PIE,
GraphType.LINE,
GraphType.GAUGE,
@@ -3,6 +3,7 @@ import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/h
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations';
import { getAvailableAggregateOperationsForFieldMetadataType } from '@/object-record/record-table/record-table-footer/utils/getAvailableAggregateOperationsForFieldMetadataType';
import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-record/utils/convertExtendedAggregateOperationToAggregateOperation';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
@@ -22,7 +23,7 @@ import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { IconChevronLeft } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { type AggregateOperations } from '~/generated/graphql';
import { GraphType, type AggregateOperations } from '~/generated/graphql';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
export const ChartAggregateOperationSelectionDropdownContent = ({
@@ -40,7 +41,8 @@ export const ChartAggregateOperationSelectionDropdownContent = ({
if (
widgetInEditMode?.configuration?.__typename !== 'BarChartConfiguration' &&
widgetInEditMode?.configuration?.__typename !== 'LineChartConfiguration' &&
widgetInEditMode?.configuration?.__typename !== 'NumberChartConfiguration'
widgetInEditMode?.configuration?.__typename !==
'AggregateChartConfiguration'
) {
throw new Error('Invalid configuration type');
}
@@ -71,7 +73,21 @@ export const ChartAggregateOperationSelectionDropdownContent = ({
})
: [];
const aggregateOperationsWithLabels = availableAggregateOperations.map(
const isAggregateOrGaugeChart =
widgetInEditMode.configuration.graphType === GraphType.AGGREGATE ||
widgetInEditMode.configuration.graphType === GraphType.GAUGE;
const filteredAggregateOperations = availableAggregateOperations.filter(
(operation) => {
return (
isAggregateOrGaugeChart ||
(operation !== DateAggregateOperations.EARLIEST &&
operation !== DateAggregateOperations.LATEST)
);
},
);
const aggregateOperationsWithLabels = filteredAggregateOperations.map(
(operation) => ({
operation,
label: getAggregateOperationLabel(operation),
@@ -14,7 +14,6 @@ import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/com
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro';
import { useState } from 'react';
import { isFieldMetadataDateKind } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
@@ -32,7 +31,7 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => {
if (
configuration?.__typename !== 'BarChartConfiguration' &&
configuration?.__typename !== 'LineChartConfiguration' &&
configuration?.__typename !== 'NumberChartConfiguration'
configuration?.__typename !== 'AggregateChartConfiguration'
) {
throw new Error('Invalid configuration type');
}
@@ -61,12 +60,7 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => {
searchQuery,
getSearchableValues: (item) => [item.label, item.name],
// TODO: remove the relation filter once group by is supported for relation fields
}).filter(
(field) =>
!isFieldRelation(field) &&
!field.isSystem &&
!isFieldMetadataDateKind(field.type),
);
}).filter((field) => !isFieldRelation(field) && !field.isSystem);
const { getIcon } = useIcons();
@@ -3,7 +3,7 @@ import { DATA_DISPLAY_AGGREGATE_SETTING } from '@/command-menu/pages/page-layout
import { FILTER_SETTING } from '@/command-menu/pages/page-layout/constants/settings/FilterSetting';
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
export const NUMBER_CHART_SETTINGS: ChartSettingsGroup[] = [
export const AGGREGATE_CHART_SETTINGS: ChartSettingsGroup[] = [
{
heading: 'Data',
items: [
@@ -1,19 +1,19 @@
import { AGGREGATE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/AggregateChartSettings';
import { GAUGE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/GaugeChartSettings';
import { LINE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/LineChartSettings';
import { NUMBER_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/NumberChartSettings';
import { PIE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/PieChartSettings';
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
import { getBarChartSettings } from '@/command-menu/pages/page-layout/utils/getBarChartSettings';
import { type MessageDescriptor } from '@lingui/core';
import { msg } from '@lingui/core/macro';
import {
Icon123,
IconChartBar,
IconChartBarHorizontal,
IconChartLine,
IconChartPie,
type IconComponent,
IconGauge,
IconSum,
} from 'twenty-ui/display';
import { GraphType } from '~/generated-metadata/graphql';
@@ -26,12 +26,12 @@ export const GRAPH_TYPE_INFORMATION: Record<
}
> = {
[GraphType.VERTICAL_BAR]: {
label: msg`Vertical Bar`,
label: msg`Vertical`,
icon: IconChartBar,
settings: getBarChartSettings(GraphType.VERTICAL_BAR),
},
[GraphType.HORIZONTAL_BAR]: {
label: msg`Horizontal Bar`,
label: msg`Horizontal`,
icon: IconChartBarHorizontal,
settings: getBarChartSettings(GraphType.HORIZONTAL_BAR),
},
@@ -45,10 +45,10 @@ export const GRAPH_TYPE_INFORMATION: Record<
icon: IconChartLine,
settings: LINE_CHART_SETTINGS,
},
[GraphType.NUMBER]: {
label: msg`Number`,
icon: Icon123,
settings: NUMBER_CHART_SETTINGS,
[GraphType.AGGREGATE]: {
label: msg`Aggregate`,
icon: IconSum,
settings: AGGREGATE_CHART_SETTINGS,
},
[GraphType.GAUGE]: {
label: msg`Gauge`,
@@ -5,6 +5,6 @@ export const GRAPH_TYPE_TO_CONFIG_TYPENAME = {
[GraphType.HORIZONTAL_BAR]: 'BarChartConfiguration',
[GraphType.LINE]: 'LineChartConfiguration',
[GraphType.PIE]: 'PieChartConfiguration',
[GraphType.NUMBER]: 'NumberChartConfiguration',
[GraphType.AGGREGATE]: 'AggregateChartConfiguration',
[GraphType.GAUGE]: 'GaugeChartConfiguration',
} as const;
@@ -2,11 +2,11 @@ import { ChartFieldSelectionForAggregateOperationDropdownContent } from '@/comma
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 { Icon123 } from 'twenty-ui/display';
import { IconSum } from 'twenty-ui/display';
export const DATA_DISPLAY_AGGREGATE_SETTING: ChartSettingsItem = {
isBoolean: false,
Icon: Icon123,
Icon: IconSum,
label: CHART_CONFIGURATION_SETTING_LABELS.DATA_ON_DISPLAY_AGGREGATE,
id: CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_AGGREGATE,
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE],
@@ -6,6 +6,7 @@ import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout
import { getFieldLabelWithSubField } from '@/command-menu/pages/page-layout/utils/getFieldLabelWithSubField';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
import { useRecoilValue } from 'recoil';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { capitalize, isDefined } from 'twenty-shared/utils';
@@ -83,7 +84,11 @@ export const useChartSettingsValues = ({
fieldMetadataItem.id === configuration.aggregateFieldMetadataId,
);
const yAxisAggregateOperation = configuration.aggregateOperation;
const aggregateOperation =
convertAggregateOperationToExtendedAggregateOperation(
configuration.aggregateOperation,
aggregateField?.type,
);
const xAxisOrderByLabel =
isDefined(xAxisOrderBy) && isDefined(groupByFieldXId)
@@ -131,11 +136,11 @@ export const useChartSettingsValues = ({
case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_Y:
case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_AGGREGATE: {
const hasAggregateLabel = isDefined(aggregateField?.label);
const hasAggregateOperation = isDefined(yAxisAggregateOperation);
const hasAggregateOperation = isDefined(aggregateOperation);
return `${aggregateField?.label ?? ''}${
hasAggregateLabel && hasAggregateOperation
? ` (${getAggregateOperationLabel(yAxisAggregateOperation)})`
? ` (${getAggregateOperationLabel(aggregateOperation)})`
: ''
}`;
}
@@ -1,8 +1,8 @@
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type GaugeChartConfiguration,
type LineChartConfiguration,
type NumberChartConfiguration,
type PieChartConfiguration,
} from '~/generated/graphql';
@@ -10,5 +10,5 @@ export type ChartConfiguration =
| BarChartConfiguration
| LineChartConfiguration
| PieChartConfiguration
| NumberChartConfiguration
| AggregateChartConfiguration
| GaugeChartConfiguration;
@@ -1,8 +1,8 @@
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type GaugeChartConfiguration,
type LineChartConfiguration,
type NumberChartConfiguration,
type PieChartConfiguration,
} from '~/generated/graphql';
@@ -10,5 +10,5 @@ export type ChartWidgetConfiguration =
| BarChartConfiguration
| GaugeChartConfiguration
| LineChartConfiguration
| NumberChartConfiguration
| AggregateChartConfiguration
| PieChartConfiguration;
@@ -88,8 +88,8 @@ const mixedGraphsPageLayoutMocks = {
columnSpan: 3,
},
configuration: {
__typename: 'NumberChartConfiguration',
graphType: GraphType.NUMBER,
__typename: 'AggregateChartConfiguration',
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
},
@@ -6,7 +6,7 @@ type WidgetSizeConfig = {
};
export const WIDGET_SIZES: Record<GraphType, WidgetSizeConfig> = {
[GraphType.NUMBER]: {
[GraphType.AGGREGATE]: {
default: { w: 3, h: 2 },
minimum: { w: 2, h: 2 },
},
@@ -67,7 +67,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql`
description
filter
}
... on NumberChartConfiguration {
... on AggregateChartConfiguration {
graphType
aggregateFieldMetadataId
aggregateOperation
@@ -1,6 +1,7 @@
import { useCreatePageLayoutGraphWidget } from '@/page-layout/hooks/useCreatePageLayoutGraphWidget';
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetFieldSelection';
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';
@@ -13,7 +14,6 @@ import {
PAGE_LAYOUT_TEST_INSTANCE_ID,
PageLayoutTestWrapper,
} from './PageLayoutTestWrapper';
import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetFieldSelection';
jest.mock('uuid', () => ({
v4: jest.fn(() => 'mock-uuid'),
@@ -160,7 +160,7 @@ describe('useCreatePageLayoutGraphWidget', () => {
});
const graphTypes = [
GraphType.NUMBER,
GraphType.AGGREGATE,
GraphType.GAUGE,
GraphType.PIE,
GraphType.VERTICAL_BAR,
@@ -169,7 +169,7 @@ describe('useCreatePageLayoutGraphWidget', () => {
const mockFieldSelections: Partial<
Record<GraphType, GraphWidgetFieldSelection>
> = {
[GraphType.NUMBER]: {
[GraphType.AGGREGATE]: {
objectMetadataId: 'test-object-id',
aggregateFieldMetadataId: 'test-aggregate-field-id',
},
@@ -14,7 +14,7 @@ describe('addWidgetToTab', () => {
title: 'Test Widget',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
displayDataLabel: false,
@@ -22,7 +22,7 @@ describe('convertLayoutsToWidgets', () => {
columnSpan: 2,
},
configuration: {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
displayDataLabel: false,
@@ -29,7 +29,7 @@ describe('convertPageLayoutToTabLayouts', () => {
title: 'Widget 1',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
displayDataLabel: false,
@@ -135,11 +135,11 @@ describe('extractFieldMetadataIdsFromWidget', () => {
expect(result).toContain('field-2');
});
it('should extract field IDs from NumberChartConfiguration', () => {
it('should extract field IDs from AggregateChartConfiguration', () => {
const widget = createMockWidget({
configuration: {
__typename: 'NumberChartConfiguration' as const,
graphType: GraphType.NUMBER,
__typename: 'AggregateChartConfiguration' as const,
graphType: GraphType.AGGREGATE,
aggregateFieldMetadataId: 'field-1',
aggregateOperation: AggregateOperations.AVG,
displayDataLabel: false,
@@ -22,7 +22,7 @@ describe('removeWidgetFromTab', () => {
title: 'Widget 1',
type: WidgetType.GRAPH,
configuration: {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: 'id',
displayDataLabel: false,
@@ -18,13 +18,13 @@ const createDefaultGraphConfiguration = (
fieldSelection?: GraphWidgetFieldSelection,
): WidgetConfiguration | null => {
switch (graphType) {
case GraphType.NUMBER:
case GraphType.AGGREGATE:
if (!isDefined(fieldSelection?.aggregateFieldMetadataId)) {
return null;
}
return {
__typename: 'NumberChartConfiguration',
graphType: GraphType.NUMBER,
__typename: 'AggregateChartConfiguration',
graphType: GraphType.AGGREGATE,
aggregateFieldMetadataId: fieldSelection.aggregateFieldMetadataId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -34,7 +34,7 @@ export const extractFieldMetadataIdsFromWidget = (
config.groupByFieldMetadataId,
].filter(isDefined);
case 'NumberChartConfiguration':
case 'AggregateChartConfiguration':
return [config.aggregateFieldMetadataId].filter(isDefined);
case 'GaugeChartConfiguration':
@@ -2,7 +2,7 @@ import { GraphType } from '~/generated-metadata/graphql';
export const getDefaultWidgetData = (graphType: GraphType) => {
switch (graphType) {
case GraphType.NUMBER:
case GraphType.AGGREGATE:
return {
value: '1,234',
trendPercentage: 15.2,
@@ -2,7 +2,7 @@ import { GraphType } from '~/generated/graphql';
export const getWidgetTitle = (graphType: GraphType, index: number): string => {
const baseNames: Record<GraphType, string> = {
[GraphType.NUMBER]: 'Number',
[GraphType.AGGREGATE]: 'Number',
[GraphType.GAUGE]: 'Gauge',
[GraphType.PIE]: 'Pie Chart',
[GraphType.VERTICAL_BAR]: 'Vertical Bar Chart',
@@ -169,8 +169,8 @@ export const WithNumberChart: Story = {
columnSpan: 3,
},
configuration: {
__typename: 'NumberChartConfiguration',
graphType: GraphType.NUMBER,
__typename: 'AggregateChartConfiguration',
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
displayDataLabel: true,
@@ -277,8 +277,8 @@ export const SmallWidget: Story = {
columnSpan: 2,
},
configuration: {
__typename: 'NumberChartConfiguration',
graphType: GraphType.NUMBER,
__typename: 'AggregateChartConfiguration',
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
displayDataLabel: true,
@@ -409,8 +409,8 @@ export const WideWidget: Story = {
columnSpan: 8,
},
configuration: {
__typename: 'NumberChartConfiguration',
graphType: GraphType.NUMBER,
__typename: 'AggregateChartConfiguration',
graphType: GraphType.AGGREGATE,
aggregateOperation: AggregateOperations.COUNT,
aggregateFieldMetadataId: idField.id,
displayDataLabel: true,
@@ -2,8 +2,8 @@ import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMeta
import { getDefaultWidgetData } from '@/page-layout/utils/getDefaultWidgetData';
import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay';
import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader';
import { GraphWidgetAggregateChartRenderer } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer';
import { GraphWidgetBarChartRenderer } from '@/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer';
import { GraphWidgetNumberChartRenderer } from '@/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChartRenderer';
import { areChartConfigurationFieldsValidForQuery } from '@/page-layout/widgets/graph/utils/areChartConfigurationFieldsValidForQuery';
import { lazy, Suspense } from 'react';
import { GraphType, type PageLayoutWidget } from '~/generated/graphql';
@@ -63,8 +63,8 @@ export const GraphWidget = ({
}
switch (graphType) {
case GraphType.NUMBER:
return <GraphWidgetNumberChartRenderer widget={widget} />;
case GraphType.AGGREGATE:
return <GraphWidgetAggregateChartRenderer widget={widget} />;
case GraphType.GAUGE:
return (
@@ -1,16 +1,16 @@
import { type Meta, type StoryObj } from '@storybook/react';
import { GraphWidgetAggregateChart } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart';
import { ComponentDecorator } from 'twenty-ui/testing';
import { GraphWidgetNumberChart } from '@/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart';
const meta: Meta<typeof GraphWidgetNumberChart> = {
title: 'Modules/PageLayout/Widgets/GraphWidgetNumberChart',
component: GraphWidgetNumberChart,
const meta: Meta<typeof GraphWidgetAggregateChart> = {
title: 'Modules/PageLayout/Widgets/GraphWidgetAggregateChart',
component: GraphWidgetAggregateChart,
decorators: [ComponentDecorator],
};
export default meta;
type Story = StoryObj<typeof GraphWidgetNumberChart>;
type Story = StoryObj<typeof GraphWidgetAggregateChart>;
export const Default: Story = {
args: {
@@ -1,4 +1,4 @@
import { formatNumberChartTrend } from '@/page-layout/widgets/graph/graphWidgetNumberChart/utils/formatNumberChartTrend';
import { formatNumberChartTrend } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/utils/formatNumberChartTrend';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
@@ -9,7 +9,7 @@ import {
IconTrendingUp,
} from 'twenty-ui/display';
type GraphWidgetNumberChartProps = {
type GraphWidgetAggregateChartProps = {
value: string | number;
trendPercentage?: number;
};
@@ -36,13 +36,14 @@ const StyledTrendIconContainer = styled.div`
`;
const StyledH1Title = styled(H1Title)`
font-size: ${({ theme }) => theme.font.size.xxl};
margin: 0;
`;
export const GraphWidgetNumberChart = ({
export const GraphWidgetAggregateChart = ({
value,
trendPercentage,
}: GraphWidgetNumberChartProps) => {
}: GraphWidgetAggregateChartProps) => {
const theme = useTheme();
const formattedPercentage = isDefined(trendPercentage)
@@ -2,26 +2,26 @@ import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/Char
import { useGraphWidgetAggregateQuery } from '@/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery';
import { lazy, Suspense } from 'react';
import {
type NumberChartConfiguration,
type AggregateChartConfiguration,
type PageLayoutWidget,
} from '~/generated/graphql';
const GraphWidgetNumberChart = lazy(() =>
const GraphWidgetAggregateChart = lazy(() =>
import(
'@/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart'
'@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart'
).then((module) => ({
default: module.GraphWidgetNumberChart,
default: module.GraphWidgetAggregateChart,
})),
);
export const GraphWidgetNumberChartRenderer = ({
export const GraphWidgetAggregateChartRenderer = ({
widget,
}: {
widget: PageLayoutWidget;
}) => {
const { value, loading } = useGraphWidgetAggregateQuery({
objectMetadataItemId: widget.objectMetadataId,
configuration: widget.configuration as NumberChartConfiguration,
configuration: widget.configuration as AggregateChartConfiguration,
});
if (loading) {
@@ -30,7 +30,7 @@ export const GraphWidgetNumberChartRenderer = ({
return (
<Suspense fallback={<ChartSkeletonLoader />}>
<GraphWidgetNumberChart value={value ?? 0} />
<GraphWidgetAggregateChart value={value ?? '-'} />
</Suspense>
);
};
@@ -1,11 +1,11 @@
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel';
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
import { useGraphWidgetQueryCommon } from '@/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon';
import { UserContext } from '@/users/contexts/UserContext';
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { type NumberChartConfiguration } from '~/generated/graphql';
import { type AggregateChartConfiguration } from '~/generated/graphql';
import { dateLocaleState } from '~/localization/states/dateLocaleState';
export const useGraphWidgetAggregateQuery = ({
@@ -13,7 +13,7 @@ export const useGraphWidgetAggregateQuery = ({
configuration,
}: {
objectMetadataItemId: string;
configuration: NumberChartConfiguration;
configuration: AggregateChartConfiguration;
}) => {
const { objectMetadataItem, gqlOperationFilter, aggregateField } =
useGraphWidgetQueryCommon({
@@ -21,14 +21,18 @@ export const useGraphWidgetAggregateQuery = ({
configuration,
});
// TODO: Move this enum to shared
const aggregateOperation =
configuration.aggregateOperation as unknown as ExtendedAggregateOperations;
const aggregateOperation = configuration.aggregateOperation;
const extendedAggregateOperation =
convertAggregateOperationToExtendedAggregateOperation(
aggregateOperation,
aggregateField.type,
);
const { data, loading, error } = useAggregateRecords({
objectNameSingular: objectMetadataItem.nameSingular,
recordGqlFieldsAggregate: {
[aggregateField.name]: [aggregateOperation],
[aggregateField.name]: [extendedAggregateOperation],
},
filter: gqlOperationFilter,
});
@@ -40,7 +44,7 @@ export const useGraphWidgetAggregateQuery = ({
data,
objectMetadataItem,
fieldMetadataId: configuration.aggregateFieldMetadataId,
aggregateOperation,
aggregateOperation: extendedAggregateOperation,
dateFormat,
timeFormat,
timeZone,
@@ -4,8 +4,8 @@ import {
isDefined,
} from 'twenty-shared/utils';
import {
type AggregateChartConfiguration,
type BarChartConfiguration,
type NumberChartConfiguration,
} from '~/generated/graphql';
export const useGraphWidgetQueryCommon = ({
@@ -13,7 +13,7 @@ export const useGraphWidgetQueryCommon = ({
configuration,
}: {
objectMetadataItemId: string;
configuration: BarChartConfiguration | NumberChartConfiguration;
configuration: BarChartConfiguration | AggregateChartConfiguration;
}) => {
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: objectMetadataItemId,
@@ -53,7 +53,7 @@ export const areChartConfigurationFieldsValidForQuery = (
fieldExists(configuration.groupByFieldMetadataId, objectMetadataItem)
);
case 'NumberChartConfiguration':
case 'AggregateChartConfiguration':
case 'GaugeChartConfiguration':
return fieldExists(
configuration.aggregateFieldMetadataId,
@@ -17,12 +17,12 @@ import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { GraphType } from 'src/engine/core-modules/page-layout/enums/graph-type.enum';
@ObjectType('NumberChartConfiguration')
export class NumberChartConfigurationDTO {
@ObjectType('AggregateChartConfiguration')
export class AggregateChartConfigurationDTO {
@Field(() => GraphType)
@IsEnum(GraphType)
@IsNotEmpty()
graphType: GraphType.NUMBER;
graphType: GraphType.AGGREGATE;
@Field(() => UUIDScalarType)
@IsUUID()
@@ -1,10 +1,10 @@
import { createUnionType } from '@nestjs/graphql';
import { AggregateChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto';
import { BarChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto';
import { GaugeChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/gauge-chart-configuration.dto';
import { IframeConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/iframe-configuration.dto';
import { LineChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto';
import { NumberChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto';
import { PieChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto';
import { GraphType } from 'src/engine/core-modules/page-layout/enums/graph-type.enum';
import { WidgetConfigurationType } from 'src/engine/core-modules/page-layout/enums/widget-configuration-type.enum';
@@ -15,7 +15,7 @@ export const WidgetConfiguration = createUnionType({
BarChartConfigurationDTO,
LineChartConfigurationDTO,
PieChartConfigurationDTO,
NumberChartConfigurationDTO,
AggregateChartConfigurationDTO,
GaugeChartConfigurationDTO,
IframeConfigurationDTO,
],
@@ -37,8 +37,8 @@ export const WidgetConfiguration = createUnionType({
return LineChartConfigurationDTO;
case GraphType.PIE:
return PieChartConfigurationDTO;
case GraphType.NUMBER:
return NumberChartConfigurationDTO;
case GraphType.AGGREGATE:
return AggregateChartConfigurationDTO;
case GraphType.GAUGE:
return GaugeChartConfigurationDTO;
default:
@@ -62,6 +62,6 @@ export type WidgetConfigurationInterface =
| BarChartConfigurationDTO
| LineChartConfigurationDTO
| PieChartConfigurationDTO
| NumberChartConfigurationDTO
| AggregateChartConfigurationDTO
| GaugeChartConfigurationDTO
| IframeConfigurationDTO;
@@ -1,7 +1,7 @@
import { registerEnumType } from '@nestjs/graphql';
export enum GraphType {
NUMBER = 'NUMBER',
AGGREGATE = 'AGGREGATE',
GAUGE = 'GAUGE',
PIE = 'PIE',
VERTICAL_BAR = 'VERTICAL_BAR',
@@ -1,11 +1,11 @@
import { plainToInstance } from 'class-transformer';
import { validateSync, type ValidationError } from 'class-validator';
import { AggregateChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto';
import { BarChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto';
import { GaugeChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/gauge-chart-configuration.dto';
import { IframeConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/iframe-configuration.dto';
import { LineChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto';
import { NumberChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto';
import { PieChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto';
import { type WidgetConfigurationInterface } from 'src/engine/core-modules/page-layout/dtos/widget-configuration.interface';
import { GraphType } from 'src/engine/core-modules/page-layout/enums/graph-type.enum';
@@ -79,9 +79,9 @@ const validateGraphConfiguration = (
return instance;
}
case GraphType.NUMBER: {
case GraphType.AGGREGATE: {
const instance = plainToInstance(
NumberChartConfigurationDTO,
AggregateChartConfigurationDTO,
configuration,
);
@@ -94,7 +94,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 },
configuration: isDefined(opportunityAmountFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: opportunityAmountFieldId,
aggregateOperation: AggregateOperations.SUM,
displayDataLabel: true,
@@ -116,7 +116,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 3, rowSpan: 4, columnSpan: 4 },
configuration: isDefined(rocketIdFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: rocketIdFieldId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -222,7 +222,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 5, rowSpan: 5, columnSpan: 7 },
configuration: isDefined(opportunityIdFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: opportunityIdFieldId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -246,7 +246,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 },
configuration: isDefined(companyIdFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: companyIdFieldId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -326,7 +326,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 0, rowSpan: 4, columnSpan: 4 },
configuration: isDefined(companyArrFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: companyArrFieldId,
aggregateOperation: AggregateOperations.SUM,
displayDataLabel: true,
@@ -395,7 +395,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 2, column: 0, rowSpan: 4, columnSpan: 3 },
configuration: isDefined(companyLinkedinLinkFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: companyLinkedinLinkFieldId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -441,7 +441,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 0, rowSpan: 5, columnSpan: 6 },
configuration: isDefined(personIdFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: personIdFieldId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -513,7 +513,7 @@ export const getPageLayoutWidgetDataSeeds = (
gridPosition: { row: 0, column: 6, rowSpan: 6, columnSpan: 6 },
configuration: isDefined(taskIdFieldId)
? {
graphType: 'NUMBER',
graphType: 'AGGREGATE',
aggregateFieldMetadataId: taskIdFieldId,
aggregateOperation: AggregateOperations.COUNT,
displayDataLabel: true,
@@ -71,7 +71,7 @@ export const PAGE_LAYOUT_WIDGET_CONFIGURATION_FIELDS = `
color
description
}
... on NumberChartConfiguration {
... on AggregateChartConfiguration {
graphType
aggregateFieldMetadataId
aggregateOperation
@@ -17,7 +17,7 @@ export const TEST_IFRAME_CONFIG_ALTERNATIVE = {
};
export const TEST_NUMBER_CHART_CONFIG = {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateFieldMetadataId: TEST_FIELD_METADATA_ID_1,
aggregateOperation: AggregateOperations.COUNT,
label: 'Total Records',
@@ -27,7 +27,7 @@ export const TEST_NUMBER_CHART_CONFIG = {
};
export const TEST_NUMBER_CHART_CONFIG_MINIMAL = {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateFieldMetadataId: TEST_FIELD_METADATA_ID_1,
aggregateOperation: AggregateOperations.SUM,
displayDataLabel: false,
@@ -174,17 +174,17 @@ export const INVALID_IFRAME_CONFIG_EMPTY_URL = {
};
export const INVALID_NUMBER_CHART_CONFIG_MISSING_FIELDS = {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
};
export const INVALID_NUMBER_CHART_CONFIG_BAD_UUID = {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateFieldMetadataId: 'not-a-uuid',
aggregateOperation: AggregateOperations.COUNT,
};
export const INVALID_NUMBER_CHART_CONFIG_INVALID_OPERATION = {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
aggregateFieldMetadataId: TEST_FIELD_METADATA_ID_1,
aggregateOperation: 'INVALID_OP' as any,
};
@@ -218,7 +218,7 @@ export const INVALID_HORIZONTAL_BAR_CHART_CONFIG_BAD_ORDER_BY = {
};
export const CONFIG_TYPE_MISMATCH_IFRAME_WITH_GRAPH = {
graphType: GraphType.NUMBER,
graphType: GraphType.AGGREGATE,
url: 'https://example.com',
};
@@ -326,6 +326,7 @@ export {
IconStatusChange,
IconStepInto,
IconStrikethrough,
IconSum,
IconSun,
IconSunMoon,
IconSwitchHorizontal,
+1
View File
@@ -391,6 +391,7 @@ export {
IconStatusChange,
IconStepInto,
IconStrikethrough,
IconSum,
IconSun,
IconSunMoon,
IconSwitchHorizontal,
@@ -75,7 +75,6 @@ const StyledLabel = styled.div<{
font-family: ${({ theme }) => theme.font.family};
font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
line-height: 1;
max-width: 100%;
overflow: hidden;
text-align: center;