From f6c094a56fa1c63d937c03215c6eef27417fcbbb Mon Sep 17 00:00:00 2001 From: Hitarth Sheth <133380930+Hitarthsheth07@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:49:42 -0400 Subject: [PATCH] [FIX] fix navigation overflow (#7795) FIX #7733 Fixes the overflow and responsive problem on large and small devices. ![image](https://github.com/user-attachments/assets/6cd8b33f-a52f-4452-b161-9c84ebbb4cce) ![image](https://github.com/user-attachments/assets/c8c0386f-e2a2-4f96-a06e-7e37f54c0564) The 'Workspace' title is fixed and only links under it are scrolled when overflown. --------- Co-authored-by: Lucas Bordeau --- .../components/WorkspaceFavorites.tsx | 7 +- ...igationDrawerItemForObjectMetadataItem.tsx | 84 ++++++++++ .../NavigationDrawerOpenedSection.tsx | 5 - ...ionDrawerSectionForObjectMetadataItems.tsx | 158 +++++++----------- ...erSectionForObjectMetadataItemsWrapper.tsx | 6 - .../components/NavigationDrawer.tsx | 9 +- ...avigationDrawerAnimatedCollapseWrapper.tsx | 6 +- .../components/NavigationDrawerItem.tsx | 1 - .../components/NavigationDrawerSection.tsx | 2 + .../scroll/contexts/ScrollWrapperContexts.tsx | 7 +- 10 files changed, 159 insertions(+), 126 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx diff --git a/packages/twenty-front/src/modules/favorites/components/WorkspaceFavorites.tsx b/packages/twenty-front/src/modules/favorites/components/WorkspaceFavorites.tsx index cf10621140..b975799fd4 100644 --- a/packages/twenty-front/src/modules/favorites/components/WorkspaceFavorites.tsx +++ b/packages/twenty-front/src/modules/favorites/components/WorkspaceFavorites.tsx @@ -2,17 +2,13 @@ import { useFilteredObjectMetadataItemsForWorkspaceFavorites } from '@/navigatio import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems'; import { NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; -import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; -import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; -import { View } from '@/views/types/View'; export const WorkspaceFavorites = () => { - const { records: views } = usePrefetchedData(PrefetchKey.AllViews); - const { activeObjectMetadataItems: objectMetadataItemsToDisplay } = useFilteredObjectMetadataItemsForWorkspaceFavorites(); const loading = useIsPrefetchLoading(); + if (loading) { return ; } @@ -21,7 +17,6 @@ export const WorkspaceFavorites = () => { ); diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx new file mode 100644 index 0000000000..8c7f1e3ced --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx @@ -0,0 +1,84 @@ +import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; +import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; +import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; +import { NavigationDrawerItemsCollapsedContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsedContainer'; +import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem'; +import { getNavigationSubItemState } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemState'; +import { View } from '@/views/types/View'; +import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews'; +import { useLocation } from 'react-router-dom'; +import { useIcons } from 'twenty-ui'; + +export type NavigationDrawerItemForObjectMetadataItemProps = { + objectMetadataItem: ObjectMetadataItem; +}; + +export const NavigationDrawerItemForObjectMetadataItem = ({ + objectMetadataItem, +}: NavigationDrawerItemForObjectMetadataItemProps) => { + const { records: views } = usePrefetchedData(PrefetchKey.AllViews); + + const objectMetadataViews = getObjectMetadataItemViews( + objectMetadataItem.id, + views, + ); + + const { getIcon } = useIcons(); + const currentPath = useLocation().pathname; + const { getLastVisitedViewIdFromObjectMetadataItemId } = useLastVisitedView(); + + const lastVisitedViewId = getLastVisitedViewIdFromObjectMetadataItemId( + objectMetadataItem.id, + ); + + const viewId = lastVisitedViewId ?? objectMetadataViews[0]?.id; + + const navigationPath = `/objects/${objectMetadataItem.namePlural}${ + viewId ? `?view=${viewId}` : '' + }`; + + const isActive = currentPath === `/objects/${objectMetadataItem.namePlural}`; + const shouldSubItemsBeDisplayed = isActive && objectMetadataViews.length > 1; + + const sortedObjectMetadataViews = [...objectMetadataViews].sort( + (viewA, viewB) => + viewA.key === 'INDEX' ? -1 : viewA.position - viewB.position, + ); + + const selectedSubItemIndex = sortedObjectMetadataViews.findIndex( + (view) => viewId === view.id, + ); + + const subItemArrayLength = sortedObjectMetadataViews.length; + + return ( + + + {shouldSubItemsBeDisplayed && + sortedObjectMetadataViews.map((view, index) => ( + + ))} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerOpenedSection.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerOpenedSection.tsx index fb17b64307..b17ad4c310 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerOpenedSection.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerOpenedSection.tsx @@ -5,9 +5,6 @@ import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata import { NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; -import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; -import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; -import { View } from '@/views/types/View'; export const NavigationDrawerOpenedSection = () => { const { activeObjectMetadataItems } = useFilteredObjectMetadataItems(); @@ -15,7 +12,6 @@ export const NavigationDrawerOpenedSection = () => { (item) => !item.isRemote, ); - const { records: views } = usePrefetchedData(PrefetchKey.AllViews); const loading = useIsPrefetchLoading(); const currentObjectNamePlural = useParams().objectNamePlural; @@ -49,7 +45,6 @@ export const NavigationDrawerOpenedSection = () => { ) diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx index 5e666e0cf5..9960670d1b 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx @@ -1,18 +1,13 @@ -import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; +import { NavigationDrawerItemForObjectMetadataItem } from '@/object-metadata/components/NavigationDrawerItemForObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; -import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper'; -import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem'; -import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; -import { getNavigationSubItemState } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemState'; -import { View } from '@/views/types/View'; -import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews'; -import { useLocation } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; -import { useIcons } from 'twenty-ui'; +import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; -import { NavigationDrawerItemsCollapsedContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsedContainer'; +import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; +import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; +import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; + const ORDERED_STANDARD_OBJECTS = [ 'person', 'company', @@ -21,111 +16,59 @@ const ORDERED_STANDARD_OBJECTS = [ 'note', ]; +const StyledObjectsMetaDataItemsWrapper = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.betweenSiblingsGap}; + width: 100%; + margin-bottom: ${({ theme }) => theme.spacing(3)}; + flex: 1; + overflow-y: auto; +`; + export const NavigationDrawerSectionForObjectMetadataItems = ({ sectionTitle, isRemote, - views, objectMetadataItems, }: { sectionTitle: string; isRemote: boolean; - views: View[]; objectMetadataItems: ObjectMetadataItem[]; }) => { const { toggleNavigationSection, isNavigationSectionOpenState } = useNavigationSection('Objects' + (isRemote ? 'Remote' : 'Workspace')); const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); - const { getIcon } = useIcons(); - const currentPath = useLocation().pathname; - const { getLastVisitedViewIdFromObjectMetadataItemId } = useLastVisitedView(); - - const renderObjectMetadataItems = () => { - return [ - ...objectMetadataItems - .filter((item) => ORDERED_STANDARD_OBJECTS.includes(item.nameSingular)) - .sort((objectMetadataItemA, objectMetadataItemB) => { - const indexA = ORDERED_STANDARD_OBJECTS.indexOf( - objectMetadataItemA.nameSingular, - ); - const indexB = ORDERED_STANDARD_OBJECTS.indexOf( - objectMetadataItemB.nameSingular, - ); - if (indexA === -1 || indexB === -1) { - return objectMetadataItemA.nameSingular.localeCompare( - objectMetadataItemB.nameSingular, - ); - } - return indexA - indexB; - }), - ...objectMetadataItems - .filter((item) => !ORDERED_STANDARD_OBJECTS.includes(item.nameSingular)) - .sort((objectMetadataItemA, objectMetadataItemB) => { - return new Date(objectMetadataItemA.createdAt) < - new Date(objectMetadataItemB.createdAt) - ? 1 - : -1; - }), - ].map((objectMetadataItem) => { - const objectMetadataViews = getObjectMetadataItemViews( - objectMetadataItem.id, - views, + const sortedStandardObjectMetadataItems = [...objectMetadataItems] + .filter((item) => ORDERED_STANDARD_OBJECTS.includes(item.nameSingular)) + .sort((objectMetadataItemA, objectMetadataItemB) => { + const indexA = ORDERED_STANDARD_OBJECTS.indexOf( + objectMetadataItemA.nameSingular, ); - const lastVisitedViewId = getLastVisitedViewIdFromObjectMetadataItemId( - objectMetadataItem.id, - ); - const viewId = lastVisitedViewId ?? objectMetadataViews[0]?.id; - - const navigationPath = `/objects/${objectMetadataItem.namePlural}${ - viewId ? `?view=${viewId}` : '' - }`; - - const isActive = - currentPath === `/objects/${objectMetadataItem.namePlural}`; - const shouldSubItemsBeDisplayed = - isActive && objectMetadataViews.length > 1; - - const sortedObjectMetadataViews = [...objectMetadataViews].sort( - (viewA, viewB) => - viewA.key === 'INDEX' ? -1 : viewA.position - viewB.position, - ); - - const selectedSubItemIndex = sortedObjectMetadataViews.findIndex( - (view) => viewId === view.id, - ); - - const subItemArrayLength = sortedObjectMetadataViews.length; - - return ( - - - {shouldSubItemsBeDisplayed && - sortedObjectMetadataViews.map((view, index) => ( - - ))} - + const indexB = ORDERED_STANDARD_OBJECTS.indexOf( + objectMetadataItemB.nameSingular, ); + if (indexA === -1 || indexB === -1) { + return objectMetadataItemA.nameSingular.localeCompare( + objectMetadataItemB.nameSingular, + ); + } + return indexA - indexB; }); - }; + + const sortedCustomObjectMetadataItems = [...objectMetadataItems] + .filter((item) => !ORDERED_STANDARD_OBJECTS.includes(item.nameSingular)) + .sort((objectMetadataItemA, objectMetadataItemB) => { + return new Date(objectMetadataItemA.createdAt) < + new Date(objectMetadataItemB.createdAt) + ? 1 + : -1; + }); + + const objectMetadataItemsForNavigationItems = [ + ...sortedStandardObjectMetadataItems, + ...sortedCustomObjectMetadataItems, + ]; return ( objectMetadataItems.length > 0 && ( @@ -136,7 +79,18 @@ export const NavigationDrawerSectionForObjectMetadataItems = ({ onClick={() => toggleNavigationSection()} /> - {isNavigationSectionOpen && renderObjectMetadataItems()} + + + {isNavigationSectionOpen && + objectMetadataItemsForNavigationItems.map( + (objectMetadataItem) => ( + + ), + )} + + ) ); diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsWrapper.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsWrapper.tsx index 2127db1fc6..91a22ca5ab 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsWrapper.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsWrapper.tsx @@ -6,9 +6,6 @@ import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata import { NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; -import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; -import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; -import { View } from '@/views/types/View'; export const NavigationDrawerSectionForObjectMetadataItemsWrapper = ({ isRemote, @@ -21,8 +18,6 @@ export const NavigationDrawerSectionForObjectMetadataItemsWrapper = ({ const filteredActiveObjectMetadataItems = activeObjectMetadataItems.filter( (item) => (isRemote ? item.isRemote : !item.isRemote), ); - - const { records: views } = usePrefetchedData(PrefetchKey.AllViews); const loading = useIsPrefetchLoading(); if (loading && isDefined(currentUser)) { @@ -33,7 +28,6 @@ export const NavigationDrawerSectionForObjectMetadataItemsWrapper = ({ ); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx index 8fbd853a56..33e9ef1527 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx @@ -9,10 +9,10 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths'; +import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer'; import { isNavigationDrawerExpandedState } from '../../states/isNavigationDrawerExpanded'; import { NavigationDrawerBackButton } from './NavigationDrawerBackButton'; import { NavigationDrawerHeader } from './NavigationDrawerHeader'; -import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer'; export type NavigationDrawerProps = { children: ReactNode; @@ -22,7 +22,10 @@ export type NavigationDrawerProps = { title?: string; }; -const StyledAnimatedContainer = styled(motion.div)``; +const StyledAnimatedContainer = styled(motion.div)` + max-height: 100vh; + overflow: hidden; +`; const StyledContainer = styled.div<{ isSettings?: boolean; @@ -51,6 +54,8 @@ const StyledItemsContainer = styled.div` display: flex; flex-direction: column; margin-bottom: auto; + overflow: hidden; + flex: 1; `; export const NavigationDrawer = ({ diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx index 19575ff0d4..3a4d42541d 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx @@ -1,9 +1,9 @@ +import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage'; +import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { AnimationControls, motion, TargetAndTransition } from 'framer-motion'; import { useRecoilValue } from 'recoil'; -import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; -import { useTheme } from '@emotion/react'; -import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage'; const StyledAnimatedContainer = styled(motion.div)``; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx index d98fc54709..65944df37e 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx @@ -142,7 +142,6 @@ const StyledKeyBoardShortcut = styled.div` const StyledNavigationDrawerItemContainer = styled.div` display: flex; - flex-grow: 1; width: 100%; `; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx index 2ba9850332..afc7fe8037 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx @@ -6,6 +6,8 @@ const StyledSection = styled.div` gap: ${({ theme }) => theme.betweenSiblingsGap}; width: 100%; margin-bottom: ${({ theme }) => theme.spacing(3)}; + flex-shrink: 1; + overflow: hidden; `; export { StyledSection as NavigationDrawerSection }; diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/contexts/ScrollWrapperContexts.tsx b/packages/twenty-front/src/modules/ui/utilities/scroll/contexts/ScrollWrapperContexts.tsx index b6f7d2103a..1d83d1ddd9 100644 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/contexts/ScrollWrapperContexts.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/contexts/ScrollWrapperContexts.tsx @@ -17,7 +17,8 @@ export type ContextProviderName = | 'tabList' | 'releases' | 'test' - | 'showPageActivityContainer'; + | 'showPageActivityContainer' + | 'navigationDrawer'; const createScrollWrapperContext = (id: string) => createContext({ @@ -47,6 +48,8 @@ export const ReleasesScrollWrapperContext = createScrollWrapperContext('releases'); export const ShowPageActivityContainerScrollWrapperContext = createScrollWrapperContext('showPageActivityContainer'); +export const NavigationDrawerScrollWrapperContext = + createScrollWrapperContext('navigationDrawer'); export const TestScrollWrapperContext = createScrollWrapperContext('test'); export const getContextByProviderName = ( @@ -77,6 +80,8 @@ export const getContextByProviderName = ( return TestScrollWrapperContext; case 'showPageActivityContainer': return ShowPageActivityContainerScrollWrapperContext; + case 'navigationDrawer': + return NavigationDrawerScrollWrapperContext; default: throw new Error('Context Provider not available'); }