Raphaël Bosi
2025-10-07 18:33:07 +02:00
committed by GitHub
co-authored by Lucas Bordeau
parent e382730a39
commit 94546d7c09
39 changed files with 503 additions and 363 deletions
@@ -289,6 +289,8 @@ export type BarChartConfiguration = {
graphType: GraphType; graphType: GraphType;
groupByFieldMetadataIdX: Scalars['UUID']; groupByFieldMetadataIdX: Scalars['UUID'];
groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>; groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>;
groupBySubFieldNameX?: Maybe<Scalars['String']>;
groupBySubFieldNameY?: Maybe<Scalars['String']>;
omitNullValues?: Maybe<Scalars['Boolean']>; omitNullValues?: Maybe<Scalars['Boolean']>;
orderByX: GraphOrderBy; orderByX: GraphOrderBy;
orderByY?: Maybe<GraphOrderBy>; orderByY?: Maybe<GraphOrderBy>;
@@ -1598,6 +1600,8 @@ export type LineChartConfiguration = {
graphType: GraphType; graphType: GraphType;
groupByFieldMetadataIdX: Scalars['UUID']; groupByFieldMetadataIdX: Scalars['UUID'];
groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>; groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>;
groupBySubFieldNameX?: Maybe<Scalars['String']>;
groupBySubFieldNameY?: Maybe<Scalars['String']>;
omitNullValues?: Maybe<Scalars['Boolean']>; omitNullValues?: Maybe<Scalars['Boolean']>;
orderByX: GraphOrderBy; orderByX: GraphOrderBy;
orderByY?: Maybe<GraphOrderBy>; orderByY?: Maybe<GraphOrderBy>;
@@ -2955,6 +2959,7 @@ export type PieChartConfiguration = {
filter?: Maybe<Scalars['JSON']>; filter?: Maybe<Scalars['JSON']>;
graphType: GraphType; graphType: GraphType;
groupByFieldMetadataId: Scalars['UUID']; groupByFieldMetadataId: Scalars['UUID'];
groupBySubFieldName?: Maybe<Scalars['String']>;
orderBy: GraphOrderBy; orderBy: GraphOrderBy;
}; };
@@ -289,6 +289,8 @@ export type BarChartConfiguration = {
graphType: GraphType; graphType: GraphType;
groupByFieldMetadataIdX: Scalars['UUID']; groupByFieldMetadataIdX: Scalars['UUID'];
groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>; groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>;
groupBySubFieldNameX?: Maybe<Scalars['String']>;
groupBySubFieldNameY?: Maybe<Scalars['String']>;
omitNullValues?: Maybe<Scalars['Boolean']>; omitNullValues?: Maybe<Scalars['Boolean']>;
orderByX: GraphOrderBy; orderByX: GraphOrderBy;
orderByY?: Maybe<GraphOrderBy>; orderByY?: Maybe<GraphOrderBy>;
@@ -1555,6 +1557,8 @@ export type LineChartConfiguration = {
graphType: GraphType; graphType: GraphType;
groupByFieldMetadataIdX: Scalars['UUID']; groupByFieldMetadataIdX: Scalars['UUID'];
groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>; groupByFieldMetadataIdY?: Maybe<Scalars['UUID']>;
groupBySubFieldNameX?: Maybe<Scalars['String']>;
groupBySubFieldNameY?: Maybe<Scalars['String']>;
omitNullValues?: Maybe<Scalars['Boolean']>; omitNullValues?: Maybe<Scalars['Boolean']>;
orderByX: GraphOrderBy; orderByX: GraphOrderBy;
orderByY?: Maybe<GraphOrderBy>; orderByY?: Maybe<GraphOrderBy>;
@@ -2866,6 +2870,7 @@ export type PieChartConfiguration = {
filter?: Maybe<Scalars['JSON']>; filter?: Maybe<Scalars['JSON']>;
graphType: GraphType; graphType: GraphType;
groupByFieldMetadataId: Scalars['UUID']; groupByFieldMetadataId: Scalars['UUID'];
groupBySubFieldName?: Maybe<Scalars['String']>;
orderBy: GraphOrderBy; orderBy: GraphOrderBy;
}; };
@@ -1,3 +1,4 @@
import { COMMAND_MENU_LIST_SELECTABLE_LIST_ID } from '@/command-menu/constants/CommandMenuListSelectableListId';
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
@@ -11,11 +12,13 @@ export const CommandMenuDefaultSelectionEffect = ({
}: { }: {
selectableItemIds: string[]; selectableItemIds: string[];
}) => { }) => {
const { setSelectedItemId } = useSelectableList('command-menu-list'); const { setSelectedItemId } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
const selectedItemId = useRecoilComponentValue( const selectedItemId = useRecoilComponentValue(
selectedItemIdComponentState, selectedItemIdComponentState,
'command-menu-list', COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
); );
const hasUserSelectedCommand = useRecoilValue(hasUserSelectedCommandState); const hasUserSelectedCommand = useRecoilValue(hasUserSelectedCommandState);
@@ -2,11 +2,13 @@ import {
CommandMenuItem, CommandMenuItem,
type CommandMenuItemProps, type CommandMenuItemProps,
} from '@/command-menu/components/CommandMenuItem'; } from '@/command-menu/components/CommandMenuItem';
import { COMMAND_MENU_LIST_SELECTABLE_LIST_ID } from '@/command-menu/constants/CommandMenuListSelectableListId';
import { import {
Dropdown, Dropdown,
type DropdownProps, type DropdownProps,
} from '@/ui/layout/dropdown/components/Dropdown'; } from '@/ui/layout/dropdown/components/Dropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
export type CommandMenuItemDropdownProps = CommandMenuItemProps & export type CommandMenuItemDropdownProps = CommandMenuItemProps &
@@ -34,6 +36,10 @@ export const CommandMenuItemDropdown = ({
dropdownId, dropdownId,
); );
const { setSelectedItemId } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
return ( return (
<Dropdown <Dropdown
clickableComponent={ clickableComponent={
@@ -55,6 +61,9 @@ export const CommandMenuItemDropdown = ({
dropdownPlacement={dropdownPlacement} dropdownPlacement={dropdownPlacement}
dropdownOffset={dropdownOffset} dropdownOffset={dropdownOffset}
disableClickForClickableComponent={disabled} disableClickForClickableComponent={disabled}
onOpen={() => {
setSelectedItemId(id);
}}
/> />
); );
}; };
@@ -2,6 +2,7 @@ import { ActionComponent } from '@/action-menu/actions/display/components/Action
import { CommandGroup } from '@/command-menu/components/CommandGroup'; import { CommandGroup } from '@/command-menu/components/CommandGroup';
import { type ActionGroupConfig } from '@/command-menu/components/CommandMenu'; import { type ActionGroupConfig } from '@/command-menu/components/CommandMenu';
import { CommandMenuDefaultSelectionEffect } from '@/command-menu/components/CommandMenuDefaultSelectionEffect'; import { CommandMenuDefaultSelectionEffect } from '@/command-menu/components/CommandMenuDefaultSelectionEffect';
import { COMMAND_MENU_LIST_SELECTABLE_LIST_ID } from '@/command-menu/constants/CommandMenuListSelectableListId';
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight'; import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding'; import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId'; import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
@@ -74,7 +75,7 @@ export const CommandMenuList = ({
<ScrollWrapper componentInstanceId={`scroll-wrapper-command-menu`}> <ScrollWrapper componentInstanceId={`scroll-wrapper-command-menu`}>
<StyledInnerList> <StyledInnerList>
<SelectableList <SelectableList
selectableListInstanceId="command-menu-list" selectableListInstanceId={COMMAND_MENU_LIST_SELECTABLE_LIST_ID}
focusId={SIDE_PANEL_FOCUS_ID} focusId={SIDE_PANEL_FOCUS_ID}
selectableItemIdArray={selectableItemIds} selectableItemIdArray={selectableItemIds}
onSelect={() => { onSelect={() => {
@@ -0,0 +1 @@
export const COMMAND_MENU_LIST_SELECTABLE_LIST_ID = 'command-menu-list';
@@ -1,5 +1,6 @@
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/constants/CommandMenuContextChipGroupsDropdownId'; import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/constants/CommandMenuContextChipGroupsDropdownId';
import { COMMAND_MENU_LIST_SELECTABLE_LIST_ID } from '@/command-menu/constants/CommandMenuListSelectableListId';
import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId'; import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId';
import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContextStoreStates'; import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContextStoreStates';
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState'; import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
@@ -27,7 +28,9 @@ import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
export const useCommandMenuCloseAnimationCompleteCleanup = () => { export const useCommandMenuCloseAnimationCompleteCleanup = () => {
const { resetSelectedItem } = useSelectableList('command-menu-list'); const { resetSelectedItem } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
const { resetContextStoreStates } = useResetContextStoreStates(); const { resetContextStoreStates } = useResetContextStoreStates();
@@ -2,6 +2,7 @@ import { CommandGroup } from '@/command-menu/components/CommandGroup';
import { CommandMenuItemDropdown } from '@/command-menu/components/CommandMenuItemDropdown'; import { CommandMenuItemDropdown } from '@/command-menu/components/CommandMenuItemDropdown';
import { CommandMenuItemToggle } from '@/command-menu/components/CommandMenuItemToggle'; import { CommandMenuItemToggle } from '@/command-menu/components/CommandMenuItemToggle';
import { CommandMenuList } from '@/command-menu/components/CommandMenuList'; 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 { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateCommandMenuPageInfo';
import { ChartTypeSelectionSection } from '@/command-menu/pages/page-layout/components/ChartTypeSelectionSection'; import { ChartTypeSelectionSection } from '@/command-menu/pages/page-layout/components/ChartTypeSelectionSection';
import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation'; import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation';
@@ -14,11 +15,10 @@ import {
CHART_CONFIGURATION_SETTING_IDS, CHART_CONFIGURATION_SETTING_IDS,
CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP, CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP,
} from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds'; } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { getChartSettingsDropdownContent } from '@/command-menu/pages/page-layout/utils/getChartSettingsDropdownContent';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; 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 { t } from '@lingui/core/macro';
import { isNonEmptyString } from '@sniptt/guards'; import { isNonEmptyString } from '@sniptt/guards';
@@ -62,6 +62,10 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
const chartSettings = GRAPH_TYPE_INFORMATION[currentGraphType].settings; const chartSettings = GRAPH_TYPE_INFORMATION[currentGraphType].settings;
const { setSelectedItemId } = useSelectableList(
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
);
return ( return (
<CommandMenuList <CommandMenuList
commandGroups={[]} commandGroups={[]}
@@ -91,6 +95,8 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
] ]
: item.id; : item.id;
setSelectedItemId(item.id);
updateCurrentWidgetConfig({ updateCurrentWidgetConfig({
configToUpdate: { configToUpdate: {
[configKey]: !getChartSettingsValues(item.id), [configKey]: !getChartSettingsValues(item.id),
@@ -131,9 +137,7 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
dropdownId={item.id} dropdownId={item.id}
dropdownComponents={ dropdownComponents={
<DropdownContent> <DropdownContent>
<DropdownMenuItemsContainer> {item.DropdownContent && <item.DropdownContent />}
{getChartSettingsDropdownContent(item.id)}
</DropdownMenuItemsContainer>
</DropdownContent> </DropdownContent>
} }
dropdownPlacement="bottom-end" dropdownPlacement="bottom-end"
@@ -19,7 +19,6 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { useState } from 'react'; import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { IconChevronLeft } from 'twenty-ui/display'; import { IconChevronLeft } from 'twenty-ui/display';
@@ -116,7 +115,7 @@ export const ChartAggregateOperationSelectionDropdownContent = ({
/> />
} }
> >
<Trans>Y-Axis Aggregate Operation</Trans> {`${selectedField.label}`}
</DropdownMenuHeader> </DropdownMenuHeader>
<DropdownMenuSearchInput <DropdownMenuSearchInput
autoFocus autoFocus
@@ -2,7 +2,6 @@ import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pa
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout/utils/getChartAxisNameDisplayOptions'; import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout/utils/getChartAxisNameDisplayOptions';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -11,7 +10,6 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { Trans } from '@lingui/react/macro';
import { MenuItemSelect } from 'twenty-ui/navigation'; import { MenuItemSelect } from 'twenty-ui/navigation';
import { AxisNameDisplay } from '~/generated/graphql'; import { AxisNameDisplay } from '~/generated/graphql';
@@ -60,9 +58,6 @@ export const ChartAxisNameSelectionDropdownContent = () => {
return ( return (
<> <>
<DropdownMenuHeader>
<Trans>Axis Name</Trans>
</DropdownMenuHeader>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<SelectableList <SelectableList
selectableListInstanceId={dropdownId} selectableListInstanceId={dropdownId}
@@ -2,7 +2,6 @@ import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pa
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration'; import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
@@ -13,7 +12,6 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { useState } from 'react'; import { useState } from 'react';
import { capitalize, isDefined } from 'twenty-shared/utils'; import { capitalize, isDefined } from 'twenty-shared/utils';
import { ColorSample } from 'twenty-ui/display'; import { ColorSample } from 'twenty-ui/display';
@@ -75,9 +73,6 @@ export const ChartColorSelectionDropdownContent = () => {
return ( return (
<> <>
<DropdownMenuHeader>
<Trans>Color</Trans>
</DropdownMenuHeader>
<DropdownMenuSearchInput <DropdownMenuSearchInput
autoFocus autoFocus
type="text" type="text"
@@ -3,7 +3,6 @@ import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/h
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
@@ -15,7 +14,6 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { useState } from 'react'; import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display'; import { useIcons } from 'twenty-ui/display';
@@ -74,9 +72,6 @@ export const ChartDataSourceDropdownContent = () => {
return ( return (
<> <>
<DropdownMenuHeader>
<Trans>Source</Trans>
</DropdownMenuHeader>
<DropdownMenuSearchInput <DropdownMenuSearchInput
autoFocus autoFocus
type="text" type="text"
@@ -1,123 +0,0 @@
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
export const ChartFieldSelectionDropdownContent = () => {
const [searchQuery, setSearchQuery] = useState('');
const { objectMetadataItems } = useObjectMetadataItems();
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
if (
widgetInEditMode?.configuration?.__typename !== 'BarChartConfiguration' &&
widgetInEditMode?.configuration?.__typename !== 'LineChartConfiguration'
) {
throw new Error('Invalid configuration type');
}
const currentXAxisFieldMetadataId =
widgetInEditMode.configuration.groupByFieldMetadataIdX;
const sourceObjectMetadataItem = objectMetadataItems.find(
(item) => item.id === widgetInEditMode.objectMetadataId,
);
const dropdownId = useAvailableComponentInstanceIdOrThrow(
DropdownComponentInstanceContext,
);
const selectedItemId = useRecoilComponentValue(
selectedItemIdComponentState,
dropdownId,
);
const availableFieldMetadataItems = filterBySearchQuery({
items: sourceObjectMetadataItem?.fields || [],
searchQuery,
getSearchableValues: (item) => [item.label, item.name],
});
const { updateCurrentWidgetConfig } =
useUpdateCurrentWidgetConfig(pageLayoutId);
const { closeDropdown } = useCloseDropdown();
const { getIcon } = useIcons();
if (!isDefined(sourceObjectMetadataItem)) {
return null;
}
const handleSelectField = (fieldMetadataId: string) => {
updateCurrentWidgetConfig({
configToUpdate: {
groupByFieldMetadataIdX: fieldMetadataId,
},
});
closeDropdown();
};
return (
<>
<DropdownMenuHeader>
<Trans>X-Axis Field</Trans>
</DropdownMenuHeader>
<DropdownMenuSearchInput
autoFocus
type="text"
placeholder={t`Search fields`}
onChange={(event) => setSearchQuery(event.target.value)}
value={searchQuery}
/>
<DropdownMenuSeparator />
<DropdownMenuItemsContainer>
<SelectableList
selectableListInstanceId={dropdownId}
focusId={dropdownId}
selectableItemIdArray={availableFieldMetadataItems.map(
(item) => item.id,
)}
>
{availableFieldMetadataItems.map((fieldMetadataItem) => (
<SelectableListItem
key={fieldMetadataItem.id}
itemId={fieldMetadataItem.id}
onEnter={() => {
handleSelectField(fieldMetadataItem.id);
}}
>
<MenuItemSelect
text={fieldMetadataItem.label}
selected={currentXAxisFieldMetadataId === fieldMetadataItem.id}
focused={selectedItemId === fieldMetadataItem.id}
LeftIcon={getIcon(fieldMetadataItem.icon)}
onClick={() => {
handleSelectField(fieldMetadataItem.id);
}}
/>
</SelectableListItem>
))}
</SelectableList>
</DropdownMenuItemsContainer>
</>
);
};
@@ -2,7 +2,7 @@ import { ChartAggregateOperationSelectionDropdownContent } from '@/command-menu/
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
@@ -13,7 +13,6 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { useState } from 'react'; import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display'; import { useIcons } from 'twenty-ui/display';
@@ -59,7 +58,8 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => {
items: sourceObjectMetadataItem?.fields || [], items: sourceObjectMetadataItem?.fields || [],
searchQuery, searchQuery,
getSearchableValues: (item) => [item.label, item.name], getSearchableValues: (item) => [item.label, item.name],
}); // TODO: remove this once group by is supported for relation fields
}).filter((field) => !isFieldRelation(field));
const { getIcon } = useIcons(); const { getIcon } = useIcons();
@@ -78,9 +78,6 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => {
return ( return (
<> <>
<DropdownMenuHeader>
<Trans>Y-Axis Field</Trans>
</DropdownMenuHeader>
<DropdownMenuSearchInput <DropdownMenuSearchInput
autoFocus autoFocus
type="text" type="text"
@@ -0,0 +1,94 @@
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
import { ICON_NAME_BY_SUB_FIELD } from '@/object-record/record-filter/constants/IconNameBySubField';
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
import { type CompositeFieldType } from '@/settings/data-model/types/CompositeFieldType';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { IconChevronLeft, useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
type ChartGroupByFieldSelectionCompositeFieldViewProps = {
compositeField: FieldMetadataItem;
currentSubFieldName: string | undefined;
onBack: () => void;
onSelectSubField: (subFieldName: string) => void;
};
export const ChartGroupByFieldSelectionCompositeFieldView = ({
compositeField,
currentSubFieldName,
onBack,
onSelectSubField,
}: ChartGroupByFieldSelectionCompositeFieldViewProps) => {
const { getIcon } = useIcons();
const dropdownId = useAvailableComponentInstanceIdOrThrow(
DropdownComponentInstanceContext,
);
const selectedItemId = useRecoilComponentValue(
selectedItemIdComponentState,
dropdownId,
);
const compositeFieldType = compositeField.type as CompositeFieldType;
const subFieldNames = SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS[
compositeFieldType
].subFields.map((subField) => subField.subFieldName);
return (
<>
<DropdownMenuHeader
StartComponent={
<DropdownMenuHeaderLeftComponent
onClick={onBack}
Icon={IconChevronLeft}
/>
}
>
{compositeField.label}
</DropdownMenuHeader>
<DropdownMenuItemsContainer>
<SelectableList
selectableListInstanceId={dropdownId}
focusId={dropdownId}
selectableItemIdArray={subFieldNames}
>
{subFieldNames.map((subFieldName) => (
<SelectableListItem
key={subFieldName}
itemId={subFieldName}
onEnter={() => {
onSelectSubField(subFieldName);
}}
>
<MenuItemSelect
text={getCompositeSubFieldLabel(
compositeFieldType,
subFieldName,
)}
selected={currentSubFieldName === subFieldName}
focused={selectedItemId === subFieldName}
onClick={() => {
onSelectSubField(subFieldName);
}}
LeftIcon={getIcon(
ICON_NAME_BY_SUB_FIELD[subFieldName] ?? compositeField.icon,
)}
/>
</SelectableListItem>
))}
</SelectableList>
</DropdownMenuItemsContainer>
</>
);
};
@@ -1,125 +1,16 @@
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { ChartGroupByFieldSelectionDropdownContentBase } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContentBase';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; import {
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; type BarChartConfiguration,
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; type LineChartConfiguration,
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; } from '~/generated/graphql';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
export const ChartGroupByFieldSelectionDropdownContent = () => { export const ChartGroupByFieldSelectionDropdownContent = () => {
const [searchQuery, setSearchQuery] = useState('');
const { objectMetadataItems } = useObjectMetadataItems();
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
if (
widgetInEditMode?.configuration?.__typename !== 'BarChartConfiguration' &&
widgetInEditMode?.configuration?.__typename !== 'LineChartConfiguration'
) {
throw new Error('Invalid configuration type');
}
const currentGroupByFieldMetadataId =
widgetInEditMode.configuration.groupByFieldMetadataIdY;
const sourceObjectMetadataItem = objectMetadataItems.find(
(item) => item.id === widgetInEditMode.objectMetadataId,
);
const dropdownId = useAvailableComponentInstanceIdOrThrow(
DropdownComponentInstanceContext,
);
const selectedItemId = useRecoilComponentValue(
selectedItemIdComponentState,
dropdownId,
);
const availableFieldMetadataItems = filterBySearchQuery({
items: sourceObjectMetadataItem?.fields || [],
searchQuery,
getSearchableValues: (item) => [item.label, item.name],
});
const { updateCurrentWidgetConfig } =
useUpdateCurrentWidgetConfig(pageLayoutId);
const { closeDropdown } = useCloseDropdown();
const { getIcon } = useIcons();
if (!isDefined(sourceObjectMetadataItem)) {
return null;
}
const handleSelectField = (fieldMetadataId: string) => {
updateCurrentWidgetConfig({
configToUpdate: {
groupByFieldMetadataIdY: fieldMetadataId,
},
});
closeDropdown();
};
return ( return (
<> <ChartGroupByFieldSelectionDropdownContentBase<
<DropdownMenuHeader> BarChartConfiguration | LineChartConfiguration
<Trans>Y-Axis Group By Field</Trans> >
</DropdownMenuHeader> fieldMetadataIdKey="groupByFieldMetadataIdY"
<DropdownMenuSearchInput subFieldNameKey="groupBySubFieldNameY"
autoFocus />
type="text"
placeholder={t`Search fields`}
onChange={(event) => setSearchQuery(event.target.value)}
value={searchQuery}
/>
<DropdownMenuSeparator />
<DropdownMenuItemsContainer>
<SelectableList
selectableListInstanceId={dropdownId}
focusId={dropdownId}
selectableItemIdArray={availableFieldMetadataItems.map(
(item) => item.id,
)}
>
{availableFieldMetadataItems.map((fieldMetadataItem) => (
<SelectableListItem
key={fieldMetadataItem.id}
itemId={fieldMetadataItem.id}
onEnter={() => {
handleSelectField(fieldMetadataItem.id);
}}
>
<MenuItemSelect
text={fieldMetadataItem.label}
selected={
currentGroupByFieldMetadataId === fieldMetadataItem.id
}
focused={selectedItemId === fieldMetadataItem.id}
LeftIcon={getIcon(fieldMetadataItem.icon)}
onClick={() => {
handleSelectField(fieldMetadataItem.id);
}}
/>
</SelectableListItem>
))}
</SelectableList>
</DropdownMenuItemsContainer>
</>
); );
}; };
@@ -0,0 +1,187 @@
import { ChartGroupByFieldSelectionCompositeFieldView } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionCompositeFieldView';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { t } from '@lingui/core/macro';
import { useMemo, useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
type ChartGroupByFieldSelectionDropdownContentBaseProps<
T extends ChartConfiguration,
> = {
fieldMetadataIdKey: keyof T;
subFieldNameKey: keyof T;
};
export const ChartGroupByFieldSelectionDropdownContentBase = <
T extends ChartConfiguration,
>({
fieldMetadataIdKey,
subFieldNameKey,
}: ChartGroupByFieldSelectionDropdownContentBaseProps<T>) => {
const [searchQuery, setSearchQuery] = useState('');
const [selectedCompositeField, setSelectedCompositeField] =
useState<FieldMetadataItem | null>(null);
const { objectMetadataItems } = useObjectMetadataItems();
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
const configuration = widgetInEditMode?.configuration as T;
const currentGroupByFieldMetadataId = configuration?.[fieldMetadataIdKey] as
| string
| undefined;
const currentSubFieldName = configuration?.[subFieldNameKey] as
| string
| undefined;
const sourceObjectMetadataItem = objectMetadataItems.find(
(item) => item.id === widgetInEditMode?.objectMetadataId,
);
const dropdownId = useAvailableComponentInstanceIdOrThrow(
DropdownComponentInstanceContext,
);
const selectedItemId = useRecoilComponentValue(
selectedItemIdComponentState,
dropdownId,
);
const availableFieldMetadataItems = useMemo(
() =>
filterBySearchQuery({
items: sourceObjectMetadataItem?.fields || [],
searchQuery,
getSearchableValues: (item) => [item.label, item.name],
// TODO: remove this once group by is supported for relation fields
}).filter((field) => !isFieldRelation(field)),
[sourceObjectMetadataItem?.fields, searchQuery],
);
const { updateCurrentWidgetConfig } =
useUpdateCurrentWidgetConfig(pageLayoutId);
const { closeDropdown } = useCloseDropdown();
const { getIcon } = useIcons();
if (!isDefined(sourceObjectMetadataItem)) {
return null;
}
const handleSelectField = (fieldMetadataItem: FieldMetadataItem) => {
if (isCompositeFieldType(fieldMetadataItem.type)) {
setSelectedCompositeField(fieldMetadataItem);
} else {
updateCurrentWidgetConfig({
configToUpdate: {
[fieldMetadataIdKey]: fieldMetadataItem.id,
[subFieldNameKey]: null,
},
});
closeDropdown();
}
};
const handleBack = () => {
setSelectedCompositeField(null);
};
const handleSelectSubField = (subFieldName: string) => {
if (!isDefined(selectedCompositeField)) {
return;
}
updateCurrentWidgetConfig({
configToUpdate: {
[fieldMetadataIdKey]: selectedCompositeField.id,
[subFieldNameKey]: subFieldName,
},
});
closeDropdown();
};
if (isDefined(selectedCompositeField)) {
return (
<ChartGroupByFieldSelectionCompositeFieldView
compositeField={selectedCompositeField}
currentSubFieldName={currentSubFieldName}
onBack={handleBack}
onSelectSubField={handleSelectSubField}
/>
);
}
return (
<>
<DropdownMenuSearchInput
autoFocus
type="text"
placeholder={t`Search fields`}
onChange={(event) => setSearchQuery(event.target.value)}
value={searchQuery}
/>
<DropdownMenuSeparator />
<DropdownMenuItemsContainer>
{availableFieldMetadataItems.length === 0 ? (
<MenuItemSelect text={t`No fields found`} selected={false} disabled />
) : (
<SelectableList
selectableListInstanceId={dropdownId}
focusId={dropdownId}
selectableItemIdArray={availableFieldMetadataItems.map(
(item) => item.id,
)}
>
{availableFieldMetadataItems.map((fieldMetadataItem) => (
<SelectableListItem
key={fieldMetadataItem.id}
itemId={fieldMetadataItem.id}
onEnter={() => {
handleSelectField(fieldMetadataItem);
}}
>
<MenuItemSelect
text={fieldMetadataItem.label}
selected={
!isCompositeFieldType(fieldMetadataItem.type) &&
currentGroupByFieldMetadataId === fieldMetadataItem.id
}
focused={selectedItemId === fieldMetadataItem.id}
LeftIcon={getIcon(fieldMetadataItem.icon)}
hasSubMenu={isCompositeFieldType(fieldMetadataItem.type)}
onClick={() => {
handleSelectField(fieldMetadataItem);
}}
/>
</SelectableListItem>
))}
</SelectableList>
)}
</DropdownMenuItemsContainer>
</>
);
};
@@ -0,0 +1,11 @@
import { ChartGroupByFieldSelectionDropdownContentBase } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContentBase';
import { type PieChartConfiguration } from '~/generated/graphql';
export const ChartPieFieldSelectionDropdownContent = () => {
return (
<ChartGroupByFieldSelectionDropdownContentBase<PieChartConfiguration>
fieldMetadataIdKey="groupByFieldMetadataId"
subFieldNameKey="groupBySubFieldName"
/>
);
};
@@ -3,7 +3,6 @@ import { useGraphGroupBySortOptionLabels } from '@/command-menu/pages/page-layou
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -21,13 +20,7 @@ import {
type NumberChartConfiguration, type NumberChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
type ChartSortByGroupByFieldDropdownContentProps = { export const ChartSortByGroupByFieldDropdownContent = () => {
title: string;
};
export const ChartSortByGroupByFieldDropdownContent = ({
title,
}: ChartSortByGroupByFieldDropdownContentProps) => {
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord(); const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId); const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
@@ -74,7 +67,6 @@ export const ChartSortByGroupByFieldDropdownContent = ({
return ( return (
<> <>
<DropdownMenuHeader>{title}</DropdownMenuHeader>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<SelectableList <SelectableList
selectableListInstanceId={dropdownId} selectableListInstanceId={dropdownId}
@@ -0,0 +1,16 @@
import { ChartGroupByFieldSelectionDropdownContentBase } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContentBase';
import {
type BarChartConfiguration,
type LineChartConfiguration,
} from '~/generated/graphql';
export const ChartXAxisFieldSelectionDropdownContent = () => {
return (
<ChartGroupByFieldSelectionDropdownContentBase<
BarChartConfiguration | LineChartConfiguration
>
fieldMetadataIdKey="groupByFieldMetadataIdX"
subFieldNameKey="groupBySubFieldNameX"
/>
);
};
@@ -3,7 +3,6 @@ import { useGraphXSortOptionLabels } from '@/command-menu/pages/page-layout/hook
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -12,7 +11,6 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { Trans } from '@lingui/react/macro';
import { MenuItemSelect } from 'twenty-ui/navigation'; import { MenuItemSelect } from 'twenty-ui/navigation';
import { type GraphOrderBy } from '~/generated/graphql'; import { type GraphOrderBy } from '~/generated/graphql';
@@ -59,46 +57,38 @@ export const ChartXAxisSortBySelectionDropdownContent = () => {
}); });
return ( return (
<> <DropdownMenuItemsContainer>
<DropdownMenuHeader> <SelectableList
<Trans>X-Axis Sort By</Trans> selectableListInstanceId={dropdownId}
</DropdownMenuHeader> focusId={dropdownId}
<DropdownMenuItemsContainer> selectableItemIdArray={X_SORT_BY_OPTIONS.map((option) => option.value)}
<SelectableList >
selectableListInstanceId={dropdownId} {X_SORT_BY_OPTIONS.map((sortOption) => (
focusId={dropdownId} <SelectableListItem
selectableItemIdArray={X_SORT_BY_OPTIONS.map( key={sortOption.value}
(option) => option.value, itemId={sortOption.value}
)} onEnter={() => {
> handleSelectSortOption(sortOption.value);
{X_SORT_BY_OPTIONS.map((sortOption) => ( }}
<SelectableListItem >
key={sortOption.value} <MenuItemSelect
itemId={sortOption.value} text={getXSortOptionLabel({
onEnter={() => { graphOrderBy: sortOption.value,
groupByFieldMetadataIdX: configuration.groupByFieldMetadataIdX,
aggregateFieldMetadataId:
configuration.aggregateFieldMetadataId,
aggregateOperation: configuration.aggregateOperation,
})}
selected={currentOrderByX === sortOption.value}
focused={selectedItemId === sortOption.value}
LeftIcon={sortOption.icon}
onClick={() => {
handleSelectSortOption(sortOption.value); handleSelectSortOption(sortOption.value);
}} }}
> />
<MenuItemSelect </SelectableListItem>
text={getXSortOptionLabel({ ))}
graphOrderBy: sortOption.value, </SelectableList>
groupByFieldMetadataIdX: </DropdownMenuItemsContainer>
configuration.groupByFieldMetadataIdX,
aggregateFieldMetadataId:
configuration.aggregateFieldMetadataId,
aggregateOperation: configuration.aggregateOperation,
})}
selected={currentOrderByX === sortOption.value}
focused={selectedItemId === sortOption.value}
LeftIcon={sortOption.icon}
onClick={() => {
handleSelectSortOption(sortOption.value);
}}
/>
</SelectableListItem>
))}
</SelectableList>
</DropdownMenuItemsContainer>
</>
); );
}; };
@@ -1,3 +1,4 @@
import { ChartAxisNameSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartAxisNameSelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -8,4 +9,5 @@ export const AXIS_NAME_SETTING: ChartSettingsItem = {
Icon: IconGizmo, Icon: IconGizmo,
label: CHART_CONFIGURATION_SETTING_LABELS.AXIS_NAME, label: CHART_CONFIGURATION_SETTING_LABELS.AXIS_NAME,
id: CHART_CONFIGURATION_SETTING_IDS.AXIS_NAME, id: CHART_CONFIGURATION_SETTING_IDS.AXIS_NAME,
DropdownContent: ChartAxisNameSelectionDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartDataSourceDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartDataSourceDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -8,4 +9,5 @@ export const CHART_DATA_SOURCE_SETTING: ChartSettingsItem = {
Icon: IconDatabase, Icon: IconDatabase,
label: CHART_CONFIGURATION_SETTING_LABELS.SOURCE, label: CHART_CONFIGURATION_SETTING_LABELS.SOURCE,
id: CHART_CONFIGURATION_SETTING_IDS.SOURCE, id: CHART_CONFIGURATION_SETTING_IDS.SOURCE,
DropdownContent: ChartDataSourceDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartColorSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartColorSelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -8,4 +9,5 @@ export const COLORS_SETTING: ChartSettingsItem = {
Icon: IconColorSwatch, Icon: IconColorSwatch,
label: CHART_CONFIGURATION_SETTING_LABELS.COLORS, label: CHART_CONFIGURATION_SETTING_LABELS.COLORS,
id: CHART_CONFIGURATION_SETTING_IDS.COLORS, id: CHART_CONFIGURATION_SETTING_IDS.COLORS,
DropdownContent: ChartColorSelectionDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartXAxisFieldSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartXAxisFieldSelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -9,4 +10,5 @@ export const DATA_DISPLAY_X_SETTING: ChartSettingsItem = {
label: CHART_CONFIGURATION_SETTING_LABELS.DATA_ON_DISPLAY_X, label: CHART_CONFIGURATION_SETTING_LABELS.DATA_ON_DISPLAY_X,
id: CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_X, id: CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_X,
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE], dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE],
DropdownContent: ChartXAxisFieldSelectionDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartFieldSelectionForAggregateOperationDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionForAggregateOperationDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -9,4 +10,5 @@ export const DATA_DISPLAY_Y_SETTING: ChartSettingsItem = {
label: CHART_CONFIGURATION_SETTING_LABELS.DATA_ON_DISPLAY_Y, label: CHART_CONFIGURATION_SETTING_LABELS.DATA_ON_DISPLAY_Y,
id: CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_Y, id: CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_Y,
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE], dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE],
DropdownContent: ChartFieldSelectionForAggregateOperationDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartPieFieldSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartPieFieldSelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -8,4 +9,5 @@ export const EACH_SLICE_REPRESENTS_SETTING: ChartSettingsItem = {
Icon: IconChartPie, Icon: IconChartPie,
label: CHART_CONFIGURATION_SETTING_LABELS.EACH_SLICE_REPRESENTS, label: CHART_CONFIGURATION_SETTING_LABELS.EACH_SLICE_REPRESENTS,
id: CHART_CONFIGURATION_SETTING_IDS.EACH_SLICE_REPRESENTS, id: CHART_CONFIGURATION_SETTING_IDS.EACH_SLICE_REPRESENTS,
DropdownContent: ChartPieFieldSelectionDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartGroupByFieldSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -9,4 +10,5 @@ export const GROUP_BY_SETTING: ChartSettingsItem = {
label: CHART_CONFIGURATION_SETTING_LABELS.GROUP_BY, label: CHART_CONFIGURATION_SETTING_LABELS.GROUP_BY,
id: CHART_CONFIGURATION_SETTING_IDS.GROUP_BY, id: CHART_CONFIGURATION_SETTING_IDS.GROUP_BY,
dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE], dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE],
DropdownContent: ChartGroupByFieldSelectionDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartSortByGroupByFieldDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartSortByGroupByFieldDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -8,4 +9,5 @@ export const SORT_BY_GROUP_BY_FIELD_SETTING: ChartSettingsItem = {
Icon: IconArrowsSort, Icon: IconArrowsSort,
label: CHART_CONFIGURATION_SETTING_LABELS.SORT_BY_GROUP_BY_FIELD, label: CHART_CONFIGURATION_SETTING_LABELS.SORT_BY_GROUP_BY_FIELD,
id: CHART_CONFIGURATION_SETTING_IDS.SORT_BY_GROUP_BY_FIELD, id: CHART_CONFIGURATION_SETTING_IDS.SORT_BY_GROUP_BY_FIELD,
DropdownContent: ChartSortByGroupByFieldDropdownContent,
}; };
@@ -1,3 +1,4 @@
import { ChartXAxisSortBySelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartXAxisSortBySelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -8,4 +9,5 @@ export const SORT_BY_X_SETTING: ChartSettingsItem = {
Icon: IconArrowsSort, Icon: IconArrowsSort,
label: CHART_CONFIGURATION_SETTING_LABELS.SORT_BY_X, label: CHART_CONFIGURATION_SETTING_LABELS.SORT_BY_X,
id: CHART_CONFIGURATION_SETTING_IDS.SORT_BY_X, id: CHART_CONFIGURATION_SETTING_IDS.SORT_BY_X,
DropdownContent: ChartXAxisSortBySelectionDropdownContent,
}; };
@@ -3,9 +3,11 @@ import { useGraphXSortOptionLabels } from '@/command-menu/pages/page-layout/hook
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration'; 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 { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout/utils/getChartAxisNameDisplayOptions'; import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout/utils/getChartAxisNameDisplayOptions';
import { getFieldLabelWithSubField } from '@/command-menu/pages/page-layout/utils/getFieldLabelWithSubField';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel'; import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { capitalize, isDefined } from 'twenty-shared/utils'; import { capitalize, isDefined } from 'twenty-shared/utils';
export const useChartSettingsValues = ({ export const useChartSettingsValues = ({
@@ -43,6 +45,15 @@ export const useChartSettingsValues = ({
) )
: undefined; : undefined;
const groupBySubFieldNameXLabel =
'groupBySubFieldNameX' in configuration && isDefined(groupByFieldX)
? getFieldLabelWithSubField({
field: groupByFieldX,
subFieldName:
configuration.groupBySubFieldNameX as CompositeFieldSubFieldName,
})
: undefined;
const aggregateField = objectMetadataItem?.fields.find( const aggregateField = objectMetadataItem?.fields.find(
(fieldMetadataItem) => (fieldMetadataItem) =>
fieldMetadataItem.id === configuration.aggregateFieldMetadataId, fieldMetadataItem.id === configuration.aggregateFieldMetadataId,
@@ -66,6 +77,8 @@ export const useChartSettingsValues = ({
? getXSortOptionLabel({ ? getXSortOptionLabel({
graphOrderBy: xAxisOrderBy, graphOrderBy: xAxisOrderBy,
groupByFieldMetadataIdX: configuration.groupByFieldMetadataIdX, groupByFieldMetadataIdX: configuration.groupByFieldMetadataIdX,
groupBySubFieldNameX:
configuration.groupBySubFieldNameX as CompositeFieldSubFieldName,
aggregateFieldMetadataId: configuration.aggregateFieldMetadataId, aggregateFieldMetadataId: configuration.aggregateFieldMetadataId,
aggregateOperation: configuration.aggregateOperation, aggregateOperation: configuration.aggregateOperation,
}) })
@@ -88,6 +101,12 @@ export const useChartSettingsValues = ({
: 'groupByFieldMetadataId' in configuration : 'groupByFieldMetadataId' in configuration
? configuration.groupByFieldMetadataId ? configuration.groupByFieldMetadataId
: undefined, : undefined,
groupBySubFieldName:
'groupBySubFieldNameY' in configuration
? (configuration.groupBySubFieldNameY as CompositeFieldSubFieldName)
: 'groupBySubFieldName' in configuration
? (configuration.groupBySubFieldName as CompositeFieldSubFieldName)
: undefined,
}); });
const getChartSettingsValues = ( const getChartSettingsValues = (
@@ -97,7 +116,7 @@ export const useChartSettingsValues = ({
case CHART_CONFIGURATION_SETTING_IDS.SOURCE: case CHART_CONFIGURATION_SETTING_IDS.SOURCE:
return objectMetadataItem?.labelPlural; return objectMetadataItem?.labelPlural;
case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_X: case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_X:
return groupByFieldX?.label; return groupBySubFieldNameXLabel;
case CHART_CONFIGURATION_SETTING_IDS.COLORS: case CHART_CONFIGURATION_SETTING_IDS.COLORS:
return isDefined(configuration.color) && 'color' in configuration return isDefined(configuration.color) && 'color' in configuration
? capitalize(configuration.color) ? capitalize(configuration.color)
@@ -1,6 +1,8 @@
import { getFieldLabelWithSubField } from '@/command-menu/pages/page-layout/utils/getFieldLabelWithSubField';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { GraphOrderBy } from '~/generated/graphql'; import { GraphOrderBy } from '~/generated/graphql';
export const useGraphGroupBySortOptionLabels = ({ export const useGraphGroupBySortOptionLabels = ({
@@ -17,15 +19,20 @@ export const useGraphGroupBySortOptionLabels = ({
const getGroupBySortOptionLabel = ({ const getGroupBySortOptionLabel = ({
graphOrderBy, graphOrderBy,
groupByFieldMetadataId, groupByFieldMetadataId,
groupBySubFieldName,
}: { }: {
graphOrderBy: GraphOrderBy; graphOrderBy: GraphOrderBy;
groupByFieldMetadataId: string; groupByFieldMetadataId: string;
groupBySubFieldName?: CompositeFieldSubFieldName;
}): string => { }): string => {
const field = objectMetadataItem?.fields.find( const field = objectMetadataItem?.fields.find(
(fieldMetadataItem) => fieldMetadataItem.id === groupByFieldMetadataId, (fieldMetadataItem) => fieldMetadataItem.id === groupByFieldMetadataId,
); );
const fieldLabel = field?.label || t`Field`; const fieldLabel = getFieldLabelWithSubField({
field,
subFieldName: groupBySubFieldName,
});
switch (graphOrderBy) { switch (graphOrderBy) {
case GraphOrderBy.FIELD_ASC: case GraphOrderBy.FIELD_ASC:
@@ -1,7 +1,9 @@
import { getFieldLabelWithSubField } from '@/command-menu/pages/page-layout/utils/getFieldLabelWithSubField';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel'; import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { assertUnreachable, isDefined } from 'twenty-shared/utils'; import { assertUnreachable, isDefined } from 'twenty-shared/utils';
import { import {
type ExtendedAggregateOperations, type ExtendedAggregateOperations,
@@ -22,11 +24,13 @@ export const useGraphXSortOptionLabels = ({
const getXSortOptionLabel = ({ const getXSortOptionLabel = ({
graphOrderBy, graphOrderBy,
groupByFieldMetadataIdX, groupByFieldMetadataIdX,
groupBySubFieldNameX,
aggregateFieldMetadataId, aggregateFieldMetadataId,
aggregateOperation, aggregateOperation,
}: { }: {
graphOrderBy: GraphOrderBy; graphOrderBy: GraphOrderBy;
groupByFieldMetadataIdX: string; groupByFieldMetadataIdX: string;
groupBySubFieldNameX?: CompositeFieldSubFieldName;
aggregateFieldMetadataId?: string; aggregateFieldMetadataId?: string;
aggregateOperation?: ExtendedAggregateOperations; aggregateOperation?: ExtendedAggregateOperations;
}): string => { }): string => {
@@ -34,7 +38,10 @@ export const useGraphXSortOptionLabels = ({
(fieldMetadataItem) => fieldMetadataItem.id === groupByFieldMetadataIdX, (fieldMetadataItem) => fieldMetadataItem.id === groupByFieldMetadataIdX,
); );
const fieldLabel = groupByField?.label || t`Field`; const fieldLabel = getFieldLabelWithSubField({
field: groupByField,
subFieldName: groupBySubFieldNameX,
});
const aggregateField = objectMetadataItem?.fields.find( const aggregateField = objectMetadataItem?.fields.find(
(fieldMetadataItem) => (fieldMetadataItem) =>
@@ -1,5 +1,6 @@
import { type CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds'; import { type CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type MessageDescriptor } from '@lingui/core'; import { type MessageDescriptor } from '@lingui/core';
import { type ComponentType } from 'react';
import { type IconComponent } from 'twenty-ui/display'; import { type IconComponent } from 'twenty-ui/display';
export type ChartSettingsGroup = { export type ChartSettingsGroup = {
@@ -14,4 +15,5 @@ export type ChartSettingsItem = {
description?: string; description?: string;
isBoolean: boolean; isBoolean: boolean;
dependsOn?: CHART_CONFIGURATION_SETTING_IDS[]; dependsOn?: CHART_CONFIGURATION_SETTING_IDS[];
DropdownContent?: ComponentType;
}; };
@@ -1,35 +0,0 @@
import { ChartAxisNameSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartAxisNameSelectionDropdownContent';
import { ChartColorSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartColorSelectionDropdownContent';
import { ChartDataSourceDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartDataSourceDropdownContent';
import { ChartFieldSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionDropdownContent';
import { ChartFieldSelectionForAggregateOperationDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionForAggregateOperationDropdownContent';
import { ChartGroupByFieldSelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartGroupByFieldSelectionDropdownContent';
import { ChartSortByGroupByFieldDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartSortByGroupByFieldDropdownContent';
import { ChartXAxisSortBySelectionDropdownContent } from '@/command-menu/pages/page-layout/components/dropdown-content/ChartXAxisSortBySelectionDropdownContent';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { t } from '@lingui/core/macro';
export const getChartSettingsDropdownContent = (itemId: string) => {
switch (itemId) {
case CHART_CONFIGURATION_SETTING_IDS.SOURCE:
return <ChartDataSourceDropdownContent />;
case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_X:
return <ChartFieldSelectionDropdownContent />;
case CHART_CONFIGURATION_SETTING_IDS.SORT_BY_X:
return <ChartXAxisSortBySelectionDropdownContent />;
case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_Y:
return <ChartFieldSelectionForAggregateOperationDropdownContent />;
case CHART_CONFIGURATION_SETTING_IDS.SORT_BY_GROUP_BY_FIELD:
return (
<ChartSortByGroupByFieldDropdownContent title={t`Y-Axis Sort By`} />
);
case CHART_CONFIGURATION_SETTING_IDS.GROUP_BY:
return <ChartGroupByFieldSelectionDropdownContent />;
case CHART_CONFIGURATION_SETTING_IDS.COLORS:
return <ChartColorSelectionDropdownContent />;
case CHART_CONFIGURATION_SETTING_IDS.AXIS_NAME:
return <ChartAxisNameSelectionDropdownContent />;
default:
return <div>Configuration options will be implemented here</div>;
}
};
@@ -0,0 +1,27 @@
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
import { type CompositeFieldType } from '@/settings/data-model/types/CompositeFieldType';
import { t } from '@lingui/core/macro';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
export const getFieldLabelWithSubField = ({
field,
subFieldName,
}: {
field: FieldMetadataItem | undefined;
subFieldName?: CompositeFieldSubFieldName;
}): string => {
const subFieldNameLabel = isDefined(subFieldName)
? getCompositeSubFieldLabel(field?.type as CompositeFieldType, subFieldName)
: undefined;
const fieldLabel =
isDefined(subFieldNameLabel) && isDefined(field?.label)
? `${field.label} ${subFieldNameLabel}`
: isDefined(field?.label)
? field.label
: t`Field`;
return fieldLabel;
};
@@ -42,6 +42,11 @@ export class BarChartConfigurationDTO {
@IsNotEmpty() @IsNotEmpty()
groupByFieldMetadataIdX: string; groupByFieldMetadataIdX: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
groupBySubFieldNameX?: string;
@Field(() => GraphOrderBy) @Field(() => GraphOrderBy)
@IsEnum(GraphOrderBy) @IsEnum(GraphOrderBy)
@IsNotEmpty() @IsNotEmpty()
@@ -52,6 +57,11 @@ export class BarChartConfigurationDTO {
@IsOptional() @IsOptional()
groupByFieldMetadataIdY?: string; groupByFieldMetadataIdY?: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
groupBySubFieldNameY?: string;
@Field(() => GraphOrderBy, { nullable: true }) @Field(() => GraphOrderBy, { nullable: true })
@IsEnum(GraphOrderBy) @IsEnum(GraphOrderBy)
@IsOptional() @IsOptional()
@@ -42,6 +42,11 @@ export class LineChartConfigurationDTO {
@IsNotEmpty() @IsNotEmpty()
groupByFieldMetadataIdX: string; groupByFieldMetadataIdX: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
groupBySubFieldNameX?: string;
@Field(() => GraphOrderBy) @Field(() => GraphOrderBy)
@IsEnum(GraphOrderBy) @IsEnum(GraphOrderBy)
@IsNotEmpty() @IsNotEmpty()
@@ -52,6 +57,11 @@ export class LineChartConfigurationDTO {
@IsOptional() @IsOptional()
groupByFieldMetadataIdY?: string; groupByFieldMetadataIdY?: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
groupBySubFieldNameY?: string;
@Field(() => GraphOrderBy, { nullable: true }) @Field(() => GraphOrderBy, { nullable: true })
@IsEnum(GraphOrderBy) @IsEnum(GraphOrderBy)
@IsOptional() @IsOptional()
@@ -40,6 +40,11 @@ export class PieChartConfigurationDTO {
@IsNotEmpty() @IsNotEmpty()
groupByFieldMetadataId: string; groupByFieldMetadataId: string;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()
groupBySubFieldName?: string;
@Field(() => GraphOrderBy) @Field(() => GraphOrderBy)
@IsEnum(GraphOrderBy) @IsEnum(GraphOrderBy)
@IsNotEmpty() @IsNotEmpty()