From b567c6551ac9807df6b8a649f76fd49651a913d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?=
<71827178+bosiraphael@users.noreply.github.com>
Date: Fri, 10 Oct 2025 17:49:30 +0200
Subject: [PATCH] Improve and fix source selection in charts (#15033)
- Improvements: Hide advanced objects in a subMenu and order objects
alphabetically
- Fix: reset all fields when changing object
---
.../ChartDataSourceDropdownContent.tsx | 88 ++++++++++++++++---
1 file changed, 78 insertions(+), 10 deletions(-)
diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartDataSourceDropdownContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartDataSourceDropdownContent.tsx
index 2a8345f5de..87924a4c09 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartDataSourceDropdownContent.tsx
+++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartDataSourceDropdownContent.tsx
@@ -3,6 +3,8 @@ import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/h
import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
+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 { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
@@ -14,14 +16,19 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states
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 { IconChevronLeft, IconSettings, useIcons } from 'twenty-ui/display';
+import { MenuItem, MenuItemSelect } from 'twenty-ui/navigation';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
+const ADVANCED_OBJECTS_MENU_ITEM_ID = 'advanced-objects';
+
export const ChartDataSourceDropdownContent = () => {
const [searchQuery, setSearchQuery] = useState('');
+ const [isAdvancedObjectsMenuOpened, setIsAdvancedObjectsMenuOpened] =
+ useState(false);
const { objectMetadataItems } = useObjectMetadataItems();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
@@ -45,13 +52,23 @@ export const ChartDataSourceDropdownContent = () => {
objectPermissionsByObjectMetadataId[objectMetadataItem.id];
return (
- isDefined(objectPermissions) && objectPermissions.canReadObjectRecords
+ isDefined(objectPermissions) &&
+ objectPermissions.canReadObjectRecords &&
+ objectMetadataItem.isActive
);
},
);
+ const regularObjects = objectsWithReadAccess
+ .filter((item) => !item.isSystem)
+ .sort((a, b) => a.labelPlural.localeCompare(b.labelPlural));
+
+ const systemObjects = objectsWithReadAccess
+ .filter((item) => item.isSystem)
+ .sort((a, b) => a.labelPlural.localeCompare(b.labelPlural));
+
const availableObjectMetadataItems = filterBySearchQuery({
- items: objectsWithReadAccess,
+ items: isAdvancedObjectsMenuOpened ? systemObjects : regularObjects,
searchQuery,
getSearchableValues: (item) => [item.labelPlural, item.namePlural],
});
@@ -64,14 +81,47 @@ export const ChartDataSourceDropdownContent = () => {
const { getIcon } = useIcons();
const handleSelectSource = (objectMetadataId: string) => {
- updateCurrentWidgetConfig({
- objectMetadataId,
- });
+ if (currentSource !== objectMetadataId) {
+ updateCurrentWidgetConfig({
+ objectMetadataId,
+ configToUpdate: {
+ aggregateFieldMetadataId: null,
+ groupByFieldMetadataIdX: null,
+ groupByFieldMetadataIdY: null,
+ groupBySubFieldNameX: null,
+ groupBySubFieldNameY: null,
+ groupByFieldMetadataId: null,
+ groupBySubFieldName: null,
+ },
+ });
+ }
closeDropdown();
};
+ const handleAdvancedObjectsClick = () => {
+ setIsAdvancedObjectsMenuOpened(true);
+ setSearchQuery('');
+ };
+
+ const handleBack = () => {
+ setIsAdvancedObjectsMenuOpened(false);
+ setSearchQuery('');
+ };
+
return (
<>
+ {isAdvancedObjectsMenuOpened && (
+
+ }
+ >
+ Advanced objects
+
+ )}
{
objectMetadataItem.id,
- )}
+ selectableItemIdArray={[
+ ...availableObjectMetadataItems.map(
+ (objectMetadataItem) => objectMetadataItem.id,
+ ),
+ ...(!isAdvancedObjectsMenuOpened
+ ? [ADVANCED_OBJECTS_MENU_ITEM_ID]
+ : []),
+ ]}
>
{availableObjectMetadataItems.map((objectMetadataItem) => (
{
/>
))}
+ {!isAdvancedObjectsMenuOpened && (
+
+
+
+ )}
>