[DASHBOARDS] Add prefix and suffix setting to the aggregate chart (#16216)

https://github.com/user-attachments/assets/0103cebe-e426-42d0-a8e4-b82494ef8503
This commit is contained in:
Raphaël Bosi
2025-12-01 17:45:25 +01:00
committed by GitHub
parent c51a4a188d
commit 32f387a966
21 changed files with 288 additions and 89 deletions
@@ -151,6 +151,8 @@ export type AggregateChartConfiguration = {
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
prefix?: Maybe<Scalars['String']>;
suffix?: Maybe<Scalars['String']>;
timezone?: Maybe<Scalars['String']>;
};
@@ -151,6 +151,8 @@ export type AggregateChartConfiguration = {
format?: Maybe<Scalars['String']>;
graphType: GraphType;
label?: Maybe<Scalars['String']>;
prefix?: Maybe<Scalars['String']>;
suffix?: Maybe<Scalars['String']>;
timezone?: Maybe<Scalars['String']>;
};
@@ -0,0 +1,65 @@
import { TextInput } from '@/ui/input/components/TextInput';
import styled from '@emotion/styled';
import { useState } from 'react';
import { Key } from 'ts-key-enum';
type CommandMenuItemTextInputProps = {
value: string;
onChange: (value: string) => void;
placeholder?: string;
};
const StyledRightAlignedTextInput = styled(TextInput)`
input {
:focus {
color: ${({ theme }) => theme.font.color.primary};
}
color: ${({ theme }) => theme.font.color.tertiary};
text-align: right;
}
`;
export const CommandMenuItemTextInput = ({
value,
onChange,
placeholder,
}: CommandMenuItemTextInputProps) => {
const [draftValue, setDraftValue] = useState(value);
const handleChange = (text: string) => {
setDraftValue(text);
};
const handleCommit = () => {
onChange(draftValue);
};
const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {
event.target.select();
};
const handleBlur = () => {
handleCommit();
};
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === Key.Enter || event.key === Key.Escape) {
event.stopPropagation();
handleCommit();
} else {
event.stopPropagation();
}
};
return (
<StyledRightAlignedTextInput
value={draftValue}
sizeVariant="sm"
onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
placeholder={placeholder}
/>
);
};
@@ -1,6 +1,5 @@
import { CommandGroup } from '@/command-menu/components/CommandGroup';
import { CommandMenuList } from '@/command-menu/components/CommandMenuList';
import { COMMAND_MENU_LIST_SELECTABLE_LIST_ID } from '@/command-menu/constants/CommandMenuListSelectableListId';
import { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateCommandMenuPageInfo';
import { ChartSettingItem } from '@/command-menu/pages/page-layout/components/chart-settings/ChartSettingItem';
import { ChartLimitInfoBanner } from '@/command-menu/pages/page-layout/components/ChartLimitInfoBanner';
@@ -8,20 +7,14 @@ import { ChartTypeSelectionSection } from '@/command-menu/pages/page-layout/comp
import { CHART_SETTINGS_HEADINGS } from '@/command-menu/pages/page-layout/constants/ChartSettingsHeadings';
import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation';
import { useChartSettingsValues } from '@/command-menu/pages/page-layout/hooks/useChartSettingsValues';
import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateChartSettingInput } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingInput';
import { useUpdateChartSettingToggle } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingToggle';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useGetConfigToUpdateAfterGraphTypeChange } from '@/command-menu/pages/page-layout/hooks/useUpdateGraphTypeConfig';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { shouldHideChartSetting } from '@/command-menu/pages/page-layout/utils/shouldHideChartSetting';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { hasWidgetTooManyGroupsComponentState } from '@/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
@@ -38,14 +31,9 @@ const StyledCommandMenuContainer = styled.div`
export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
const { updateCommandMenuPageInfo } = useUpdateCommandMenuPageInfo();
const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu();
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { updateCurrentWidgetConfig } =
useUpdateCurrentWidgetConfig(pageLayoutId);
const { openDropdown } = useOpenDropdown();
const { setSelectedItemId } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
const { objectMetadataItems } = useObjectMetadataItems();
if (widget.configuration?.__typename === 'IframeConfiguration') {
@@ -60,14 +48,6 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
configuration,
});
const { updateChartSettingToggle } = useUpdateChartSettingToggle({
pageLayoutId,
objectMetadataId: widget.objectMetadataId,
configuration,
});
const { updateChartSettingInput } = useUpdateChartSettingInput(pageLayoutId);
const { getConfigToUpdateAfterGraphTypeChange } =
useGetConfigToUpdateAfterGraphTypeChange({
pageLayoutId,
@@ -178,41 +158,14 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
primaryAxisDateGranularity={primaryAxisDateGranularity}
/>
)}
{visibleItems.map((item) => {
const handleItemToggleChange = () => {
setSelectedItemId(item.id);
updateChartSettingToggle(item.id);
};
const handleItemInputChange = (value: number | null) => {
updateChartSettingInput(item.id, value);
};
const handleItemDropdownOpen = () => {
openDropdown({
dropdownComponentInstanceIdFromProps: item.id,
});
};
const handleFilterClick = () => {
navigatePageLayoutCommandMenu({
commandMenuPage: CommandMenuPages.PageLayoutGraphFilter,
});
};
return (
<ChartSettingItem
key={item.id}
item={item}
configuration={configuration}
getChartSettingsValues={getChartSettingsValues}
onToggleChange={handleItemToggleChange}
onInputChange={handleItemInputChange}
onDropdownOpen={handleItemDropdownOpen}
onFilterClick={handleFilterClick}
/>
);
})}
{visibleItems.map((item) => (
<ChartSettingItem
key={item.id}
item={item}
objectMetadataId={widget.objectMetadataId}
configuration={configuration}
/>
))}
</CommandGroup>
);
})}
@@ -1,38 +1,86 @@
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
import { CommandMenuItemDropdown } from '@/command-menu/components/CommandMenuItemDropdown';
import { CommandMenuItemNumberInput } from '@/command-menu/components/CommandMenuItemNumberInput';
import { CommandMenuItemTextInput } from '@/command-menu/components/CommandMenuItemTextInput';
import { CommandMenuItemToggle } from '@/command-menu/components/CommandMenuItemToggle';
import { COMMAND_MENU_LIST_SELECTABLE_LIST_ID } from '@/command-menu/constants/CommandMenuListSelectableListId';
import { useChartSettingsValues } from '@/command-menu/pages/page-layout/hooks/useChartSettingsValues';
import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateChartSettingInput } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingInput';
import { useUpdateChartSettingTextInput } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingTextInput';
import { useUpdateChartSettingToggle } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingToggle';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
import { isMinMaxRangeValid } from '@/command-menu/pages/page-layout/utils/isMinMaxRangeValid';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { t } from '@lingui/core/macro';
import { isString } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
type ChartSettingItemProps = {
item: ChartSettingsItem;
objectMetadataId: string;
configuration: ChartConfiguration;
getChartSettingsValues: (
itemId: CHART_CONFIGURATION_SETTING_IDS,
) => boolean | string | undefined;
onToggleChange: () => void;
onInputChange: (value: number | null) => void;
onDropdownOpen: () => void;
onFilterClick: () => void;
};
export const ChartSettingItem = ({
item,
objectMetadataId,
configuration,
getChartSettingsValues,
onToggleChange,
onInputChange,
onDropdownOpen,
onFilterClick,
}: ChartSettingItemProps) => {
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { openDropdown } = useOpenDropdown();
const { setSelectedItemId } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu();
const { getChartSettingsValues } = useChartSettingsValues({
objectMetadataId,
configuration,
});
const { updateChartSettingToggle } = useUpdateChartSettingToggle({
pageLayoutId,
objectMetadataId,
configuration,
});
const { updateChartSettingInput } = useUpdateChartSettingInput(pageLayoutId);
const { updateChartSettingTextInput } =
useUpdateChartSettingTextInput(pageLayoutId);
const handleToggleChange = () => {
setSelectedItemId(item.id);
updateChartSettingToggle(item.id);
};
const handleInputChange = (value: number | null) => {
updateChartSettingInput(item.id, value);
};
const handleTextInputChange = (value: string) => {
updateChartSettingTextInput(item.id, value);
};
const handleDropdownOpen = () => {
openDropdown({
dropdownComponentInstanceIdFromProps: item.id,
});
};
const handleFilterClick = () => {
navigatePageLayoutCommandMenu({
commandMenuPage: CommandMenuPages.PageLayoutGraphFilter,
});
};
if (item.id === CHART_CONFIGURATION_SETTING_IDS.FILTER) {
const filterValue = getChartSettingsValues(item.id);
const filterDescription = isString(filterValue) ? filterValue : undefined;
@@ -41,14 +89,14 @@ export const ChartSettingItem = ({
<SelectableListItem
key={item.id}
itemId={item.id}
onEnter={onFilterClick}
onEnter={handleFilterClick}
>
<CommandMenuItem
id={item.id}
label={t(item.label)}
Icon={item.Icon}
hasSubMenu
onClick={onFilterClick}
onClick={handleFilterClick}
description={filterDescription}
contextualTextPosition="right"
/>
@@ -56,7 +104,7 @@ export const ChartSettingItem = ({
);
}
if (isDefined(item.isInput)) {
if (isDefined(item.isNumberInput)) {
const settingValue = getChartSettingsValues(item.id);
const stringValue = isString(settingValue) ? settingValue : '';
@@ -69,7 +117,7 @@ export const ChartSettingItem = ({
RightComponent={
<CommandMenuItemNumberInput
value={stringValue}
onChange={onInputChange}
onChange={handleInputChange}
onValidate={(value) =>
!isDefined(value) ||
isMinMaxRangeValid(
@@ -90,26 +138,54 @@ export const ChartSettingItem = ({
);
}
if (isDefined(item.isTextInput)) {
const settingValue = getChartSettingsValues(item.id);
const stringValue = isString(settingValue) ? settingValue : '';
return (
<SelectableListItem key={item.id} itemId={item.id}>
<CommandMenuItem
id={item.id}
label={t(item.label)}
Icon={item.Icon}
RightComponent={
<CommandMenuItemTextInput
value={stringValue}
onChange={handleTextInputChange}
placeholder={
item.inputPlaceholder ? t(item.inputPlaceholder) : undefined
}
/>
}
/>
</SelectableListItem>
);
}
if (item.isBoolean) {
return (
<SelectableListItem
key={item.id}
itemId={item.id}
onEnter={onToggleChange}
onEnter={handleToggleChange}
>
<CommandMenuItemToggle
LeftIcon={item.Icon}
text={t(item.label)}
id={item.id}
toggled={getChartSettingsValues(item.id) as boolean}
onToggleChange={onToggleChange}
onToggleChange={handleToggleChange}
/>
</SelectableListItem>
);
}
return (
<SelectableListItem key={item.id} itemId={item.id} onEnter={onDropdownOpen}>
<SelectableListItem
key={item.id}
itemId={item.id}
onEnter={handleDropdownOpen}
>
<CommandMenuItemDropdown
Icon={item.Icon}
label={t(item.label)}
@@ -2,6 +2,8 @@ import { CHART_SETTINGS_HEADINGS } from '@/command-menu/pages/page-layout/consta
import { CHART_DATA_SOURCE_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ChartDataSourceSetting';
import { DATA_DISPLAY_AGGREGATE_SETTING } from '@/command-menu/pages/page-layout/constants/settings/DataDisplayAggregateSetting';
import { FILTER_SETTING } from '@/command-menu/pages/page-layout/constants/settings/FilterSetting';
import { PREFIX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrefixSetting';
import { SUFFIX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/SuffixSetting';
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
export const AGGREGATE_CHART_SETTINGS: ChartSettingsGroup[] = [
@@ -13,4 +15,8 @@ export const AGGREGATE_CHART_SETTINGS: ChartSettingsGroup[] = [
DATA_DISPLAY_AGGREGATE_SETTING,
],
},
{
heading: CHART_SETTINGS_HEADINGS.STYLE,
items: [PREFIX_SETTING, SUFFIX_SETTING],
},
];
@@ -24,4 +24,6 @@ export const CHART_CONFIGURATION_SETTING_LABELS = {
DATE_GRANULARITY_Y: msg`Date granularity`,
DATE_GRANULARITY: msg`Date granularity`,
SHOW_LEGEND: msg`Legend`,
PREFIX: msg`Prefix`,
SUFFIX: msg`Suffix`,
};
@@ -0,0 +1,14 @@
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 { msg } from '@lingui/core/macro';
import { IconCaretLeft } from 'twenty-ui/display';
export const PREFIX_SETTING: ChartSettingsItem = {
isBoolean: false,
Icon: IconCaretLeft,
label: CHART_CONFIGURATION_SETTING_LABELS.PREFIX,
id: CHART_CONFIGURATION_SETTING_IDS.PREFIX,
isTextInput: true,
inputPlaceholder: msg`unit`,
};
@@ -9,6 +9,6 @@ export const RANGE_MAX_SETTING: ChartSettingsItem = {
Icon: IconMathMax,
label: CHART_CONFIGURATION_SETTING_LABELS.MAX_RANGE,
id: CHART_CONFIGURATION_SETTING_IDS.MAX_RANGE,
isInput: true,
isNumberInput: true,
inputPlaceholder: msg`Max`,
};
@@ -9,6 +9,6 @@ export const RANGE_MIN_SETTING: ChartSettingsItem = {
Icon: IconMathMin,
label: CHART_CONFIGURATION_SETTING_LABELS.MIN_RANGE,
id: CHART_CONFIGURATION_SETTING_IDS.MIN_RANGE,
isInput: true,
isNumberInput: true,
inputPlaceholder: msg`Min`,
};
@@ -0,0 +1,14 @@
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 { msg } from '@lingui/core/macro';
import { IconCaretRight } from 'twenty-ui/display';
export const SUFFIX_SETTING: ChartSettingsItem = {
isBoolean: false,
Icon: IconCaretRight,
label: CHART_CONFIGURATION_SETTING_LABELS.SUFFIX,
id: CHART_CONFIGURATION_SETTING_IDS.SUFFIX,
isTextInput: true,
inputPlaceholder: msg`unit`,
};
@@ -256,6 +256,14 @@ export const useChartSettingsValues = ({
return isBarOrLineChart || isPieChart
? (configuration.displayLegend ?? true)
: true;
case CHART_CONFIGURATION_SETTING_IDS.PREFIX:
return configuration.__typename === 'AggregateChartConfiguration'
? (configuration.prefix ?? '')
: '';
case CHART_CONFIGURATION_SETTING_IDS.SUFFIX:
return configuration.__typename === 'AggregateChartConfiguration'
? (configuration.suffix ?? '')
: '';
default:
return '';
}
@@ -0,0 +1,23 @@
import { type CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { getConfigKeyFromSettingId } from '@/command-menu/pages/page-layout/utils/getConfigKeyFromSettingId';
import { useUpdateCurrentWidgetConfig } from './useUpdateCurrentWidgetConfig';
export const useUpdateChartSettingTextInput = (pageLayoutId: string) => {
const { updateCurrentWidgetConfig } =
useUpdateCurrentWidgetConfig(pageLayoutId);
const updateChartSettingTextInput = (
settingId: CHART_CONFIGURATION_SETTING_IDS,
value: string,
) => {
const configKey = getConfigKeyFromSettingId(settingId);
updateCurrentWidgetConfig({
configToUpdate: {
[configKey]: value,
},
});
};
return { updateChartSettingTextInput };
};
@@ -23,6 +23,8 @@ export enum CHART_CONFIGURATION_SETTING_IDS {
DATE_GRANULARITY_Y = 'DATE_GRANULARITY_Y',
DATE_GRANULARITY = 'DATE_GRANULARITY',
SHOW_LEGEND = 'SHOW_LEGEND',
PREFIX = 'PREFIX',
SUFFIX = 'SUFFIX',
}
export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = {
@@ -39,4 +41,6 @@ export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = {
'secondaryAxisGroupByDateGranularity',
[CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY]: 'dateGranularity',
[CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND]: 'displayLegend',
[CHART_CONFIGURATION_SETTING_IDS.PREFIX]: 'prefix',
[CHART_CONFIGURATION_SETTING_IDS.SUFFIX]: 'suffix',
} as const;
@@ -17,6 +17,7 @@ export type ChartSettingsItem = {
dependsOn?: CHART_CONFIGURATION_SETTING_IDS[];
DropdownContent?: ComponentType;
dropdownWidth?: number;
isInput?: boolean;
isNumberInput?: boolean;
isTextInput?: boolean;
inputPlaceholder?: MessageDescriptor;
};
@@ -13,7 +13,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Data Labels`,
Icon: IconChartBar,
isBoolean: true,
isInput: false,
isNumberInput: false,
};
const mockItemDependingOnSource: ChartSettingsItem = {
@@ -21,7 +21,7 @@ describe('shouldHideChartSetting', () => {
label: msg`X Axis Data`,
Icon: IconChartBar,
isBoolean: false,
isInput: false,
isNumberInput: false,
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE],
};
@@ -30,7 +30,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Sort By Group`,
Icon: IconChartBar,
isBoolean: false,
isInput: false,
isNumberInput: false,
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.GROUP_BY],
};
@@ -39,7 +39,7 @@ describe('shouldHideChartSetting', () => {
label: msg`X Axis Data`,
Icon: IconChartBar,
isBoolean: false,
isInput: false,
isNumberInput: false,
dependsOn: [
CHART_CONFIGURATION_SETTING_IDS.SOURCE,
CHART_CONFIGURATION_SETTING_IDS.GROUP_BY,
@@ -151,7 +151,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Data Labels`,
Icon: IconChartBar,
isBoolean: true,
isInput: false,
isNumberInput: false,
dependsOn: undefined,
};
@@ -170,7 +170,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Data Labels`,
Icon: IconChartBar,
isBoolean: true,
isInput: false,
isNumberInput: false,
dependsOn: [],
};
@@ -186,7 +186,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Date Granularity X`,
Icon: IconChartBar,
isBoolean: false,
isInput: false,
isNumberInput: false,
};
const mockDateGranularityYItem: ChartSettingsItem = {
@@ -194,7 +194,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Date Granularity Y`,
Icon: IconChartBar,
isBoolean: false,
isInput: false,
isNumberInput: false,
};
const mockDateGranularityItem: ChartSettingsItem = {
@@ -202,7 +202,7 @@ describe('shouldHideChartSetting', () => {
label: msg`Date Granularity`,
Icon: IconChartBar,
isBoolean: false,
isInput: false,
isNumberInput: false,
};
const mockObjectMetadataItem: ObjectMetadataItem = {
@@ -12,6 +12,8 @@ import {
type GraphWidgetAggregateChartProps = {
value: string | number;
trendPercentage?: number;
prefix?: string;
suffix?: string;
};
const StyledTrendPercentageValue = styled.span`
@@ -43,6 +45,8 @@ const StyledH1Title = styled(H1Title)`
export const GraphWidgetAggregateChart = ({
value,
trendPercentage,
prefix,
suffix,
}: GraphWidgetAggregateChartProps) => {
const theme = useTheme();
@@ -50,9 +54,14 @@ export const GraphWidgetAggregateChart = ({
? formatNumberChartTrend(trendPercentage)
: undefined;
const displayValue = `${prefix ?? ''}${value}${suffix ?? ''}`;
return (
<StyledContainer>
<StyledH1Title title={value} fontColor={H1TitleFontColor.Primary} />
<StyledH1Title
title={displayValue}
fontColor={H1TitleFontColor.Primary}
/>
{isDefined(trendPercentage) && (
<StyledTrendIconContainer>
<StyledTrendPercentageValue>
@@ -19,9 +19,11 @@ export const GraphWidgetAggregateChartRenderer = ({
}: {
widget: PageLayoutWidget;
}) => {
const configuration = widget.configuration as AggregateChartConfiguration;
const { value, loading } = useGraphWidgetAggregateQuery({
objectMetadataItemId: widget.objectMetadataId,
configuration: widget.configuration as AggregateChartConfiguration,
configuration,
});
if (loading) {
@@ -30,7 +32,11 @@ export const GraphWidgetAggregateChartRenderer = ({
return (
<Suspense fallback={<ChartSkeletonLoader />}>
<GraphWidgetAggregateChart value={value ?? '-'} />
<GraphWidgetAggregateChart
value={value ?? '-'}
prefix={configuration.prefix ?? undefined}
suffix={configuration.suffix ?? undefined}
/>
</Suspense>
);
};
@@ -73,4 +73,14 @@ export class AggregateChartConfigurationDTO {
@Min(0)
@Max(7)
firstDayOfTheWeek?: number;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
prefix?: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
suffix?: string;
}
@@ -55,6 +55,8 @@ export {
IconCalendarTime,
IconCalendarWeek,
IconCalendarX,
IconCaretLeft,
IconCaretRight,
IconChartBar,
IconChartCandle,
IconChartDots3,
+2
View File
@@ -120,6 +120,8 @@ export {
IconCalendarTime,
IconCalendarWeek,
IconCalendarX,
IconCaretLeft,
IconCaretRight,
IconChartBar,
IconChartCandle,
IconChartDots3,