Remove the heart icon button to add the view as a favorite from the top bar (#8769)
closes #8546 @Bonapara please check the behaviour, if this is what you were looking for! ;)
This commit is contained in:
@ -17,10 +17,12 @@ import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode';
|
||||
import { ViewPickerContentEditMode } from '@/views/view-picker/components/ViewPickerContentEditMode';
|
||||
import { ViewPickerContentEffect } from '@/views/view-picker/components/ViewPickerContentEffect';
|
||||
import { ViewPickerFavoriteFoldersDropdown } from '@/views/view-picker/components/ViewPickerFavoriteFoldersDropdown';
|
||||
import { ViewPickerListContent } from '@/views/view-picker/components/ViewPickerListContent';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useUpdateViewFromCurrentState } from '@/views/view-picker/hooks/useUpdateViewFromCurrentState';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const StyledDropdownLabelAdornments = styled.span`
|
||||
@ -49,6 +51,9 @@ const StyledViewName = styled.span`
|
||||
|
||||
export const ViewPickerDropdown = () => {
|
||||
const theme = useTheme();
|
||||
const isFavoriteFolderEnabled = useIsFeatureEnabled(
|
||||
'IS_FAVORITE_FOLDER_ENABLED',
|
||||
);
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
|
||||
@ -99,21 +104,33 @@ export const ViewPickerDropdown = () => {
|
||||
</StyledDropdownLabelAdornments>
|
||||
</StyledDropdownButtonContainer>
|
||||
}
|
||||
dropdownComponents={
|
||||
viewPickerMode === 'list' ? (
|
||||
<ViewPickerListContent />
|
||||
) : (
|
||||
<>
|
||||
{viewPickerMode === 'create-empty' ||
|
||||
viewPickerMode === 'create-from-current' ? (
|
||||
<ViewPickerContentCreateMode />
|
||||
) : (
|
||||
<ViewPickerContentEditMode />
|
||||
)}
|
||||
<ViewPickerContentEffect />
|
||||
</>
|
||||
)
|
||||
}
|
||||
dropdownComponents={(() => {
|
||||
switch (viewPickerMode) {
|
||||
case 'list':
|
||||
return <ViewPickerListContent />;
|
||||
case 'favorite-folders-picker':
|
||||
return (
|
||||
isFavoriteFolderEnabled && <ViewPickerFavoriteFoldersDropdown />
|
||||
);
|
||||
case 'create-empty':
|
||||
case 'create-from-current':
|
||||
return (
|
||||
<>
|
||||
<ViewPickerContentCreateMode />
|
||||
<ViewPickerContentEffect />
|
||||
</>
|
||||
);
|
||||
case 'edit':
|
||||
return (
|
||||
<>
|
||||
<ViewPickerContentEditMode />
|
||||
<ViewPickerContentEffect />
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
})()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import { FavoriteFolderPicker } from '@/favorites/favorite-folder-picker/components/FavoriteFolderPicker';
|
||||
import { FavoriteFolderPickerEffect } from '@/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect';
|
||||
import { FavoriteFolderPickerComponentInstanceContext } from '@/favorites/favorite-folder-picker/scopes/FavoriteFolderPickerScope';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { View } from '@/views/types/View';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
|
||||
export const ViewPickerFavoriteFoldersDropdown = () => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
const [viewPickerReferenceViewId] = useRecoilComponentStateV2(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
);
|
||||
|
||||
const view = views.find((view) => view.id === viewPickerReferenceViewId);
|
||||
|
||||
return (
|
||||
<FavoriteFolderPickerComponentInstanceContext
|
||||
favoriteFoldersScopeId={VIEW_PICKER_DROPDOWN_ID}
|
||||
>
|
||||
<DropdownScope dropdownScopeId={VIEW_PICKER_DROPDOWN_ID}>
|
||||
<>
|
||||
<FavoriteFolderPickerEffect record={view} />
|
||||
<FavoriteFolderPicker
|
||||
record={view}
|
||||
objectNameSingular="view"
|
||||
dropdownId={VIEW_PICKER_DROPDOWN_ID}
|
||||
/>
|
||||
</>
|
||||
</DropdownScope>
|
||||
</FavoriteFolderPickerComponentInstanceContext>
|
||||
);
|
||||
};
|
||||
@ -1,26 +1,18 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { DropResult } from '@hello-pangea/dnd';
|
||||
import { MouseEvent, useCallback } from 'react';
|
||||
import {
|
||||
IconLock,
|
||||
IconPencil,
|
||||
IconPlus,
|
||||
LightIconButtonAccent,
|
||||
MenuItem,
|
||||
MenuItemDraggable,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
import { IconPlus, MenuItem } from 'twenty-ui';
|
||||
|
||||
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
|
||||
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useChangeView } from '@/views/hooks/useChangeView';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useUpdateView } from '@/views/hooks/useUpdateView';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewPickerOptionDropdown } from '@/views/view-picker/components/ViewPickerOptionDropdown';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
import { moveArrayItem } from '~/utils/array/moveArrayItem';
|
||||
@ -39,13 +31,11 @@ export const ViewPickerListContent = () => {
|
||||
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const { closeDropdown } = useDropdown(VIEW_PICKER_DROPDOWN_ID);
|
||||
const { updateView } = useUpdateView();
|
||||
const { changeView } = useChangeView();
|
||||
|
||||
const handleViewSelect = (viewId: string) => {
|
||||
changeView(viewId);
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
const handleAddViewButtonClick = () => {
|
||||
@ -56,7 +46,7 @@ export const ViewPickerListContent = () => {
|
||||
};
|
||||
|
||||
const handleEditViewButtonClick = (
|
||||
event: MouseEvent<HTMLButtonElement>,
|
||||
event: MouseEvent<HTMLElement>,
|
||||
viewId: string,
|
||||
) => {
|
||||
event.stopPropagation();
|
||||
@ -64,8 +54,6 @@ export const ViewPickerListContent = () => {
|
||||
setViewPickerMode('edit');
|
||||
};
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const handleDragEnd = useCallback(
|
||||
(result: DropResult) => {
|
||||
if (!result.destination) return;
|
||||
@ -87,46 +75,25 @@ export const ViewPickerListContent = () => {
|
||||
<DropdownMenuItemsContainer>
|
||||
<DraggableList
|
||||
onDragEnd={handleDragEnd}
|
||||
draggableItems={viewsOnCurrentObject.map((view, index) => (
|
||||
<DraggableItem
|
||||
key={view.id}
|
||||
draggableId={view.id}
|
||||
index={index}
|
||||
isDragDisabled={viewsOnCurrentObject.length === 1}
|
||||
itemComponent={
|
||||
view.key === 'INDEX' ? (
|
||||
<MenuItemDraggable
|
||||
key={view.id}
|
||||
iconButtons={[
|
||||
{
|
||||
Icon: IconLock,
|
||||
},
|
||||
].filter(isDefined)}
|
||||
isIconDisplayedOnHoverOnly={false}
|
||||
onClick={() => handleViewSelect(view.id)}
|
||||
LeftIcon={getIcon(view.icon)}
|
||||
text={view.name}
|
||||
draggableItems={viewsOnCurrentObject.map((view, index) => {
|
||||
const isIndexView = view.key === 'INDEX';
|
||||
return (
|
||||
<DraggableItem
|
||||
key={view.id}
|
||||
draggableId={view.id}
|
||||
index={index}
|
||||
isDragDisabled={viewsOnCurrentObject.length === 1}
|
||||
itemComponent={
|
||||
<ViewPickerOptionDropdown
|
||||
view={view as View}
|
||||
handleViewSelect={handleViewSelect}
|
||||
isIndexView={isIndexView}
|
||||
onEdit={handleEditViewButtonClick}
|
||||
/>
|
||||
) : (
|
||||
<MenuItemDraggable
|
||||
key={view.id}
|
||||
iconButtons={[
|
||||
{
|
||||
Icon: IconPencil,
|
||||
onClick: (event: MouseEvent<HTMLButtonElement>) =>
|
||||
handleEditViewButtonClick(event, view.id),
|
||||
accent: 'tertiary' as LightIconButtonAccent,
|
||||
},
|
||||
].filter(isDefined)}
|
||||
isIconDisplayedOnHoverOnly={true}
|
||||
onClick={() => handleViewSelect(view.id)}
|
||||
LeftIcon={getIcon(view.icon)}
|
||||
text={view.name}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite';
|
||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { MenuItemWithOptionDropdown } from '@/ui/navigation/menu-item/components/MenuItemWithOptionDropdown';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { View } from '@/views/types/View';
|
||||
import { useDeleteViewFromCurrentState } from '@/views/view-picker/hooks/useDeleteViewFromCurrentState';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
IconHeart,
|
||||
IconLock,
|
||||
IconPencil,
|
||||
IconTrash,
|
||||
MenuItem,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
|
||||
type ViewPickerOptionDropdownProps = {
|
||||
isIndexView: boolean;
|
||||
view: View;
|
||||
onEdit: (event: React.MouseEvent<HTMLElement>, viewId: string) => void;
|
||||
handleViewSelect: (viewId: string) => void;
|
||||
};
|
||||
|
||||
export const ViewPickerOptionDropdown = ({
|
||||
isIndexView,
|
||||
onEdit,
|
||||
view,
|
||||
handleViewSelect,
|
||||
}: ViewPickerOptionDropdownProps) => {
|
||||
const { closeDropdown } = useDropdown(`view-picker-options-${view.id}`);
|
||||
const { getIcon } = useIcons();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const { deleteViewFromCurrentState } = useDeleteViewFromCurrentState();
|
||||
const setViewPickerReferenceViewId = useSetRecoilComponentStateV2(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
);
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const isFavoriteFolderEnabled = useIsFeatureEnabled(
|
||||
'IS_FAVORITE_FOLDER_ENABLED',
|
||||
);
|
||||
|
||||
const { sortedFavorites: favorites } = useFavorites();
|
||||
const { createFavorite } = useCreateFavorite();
|
||||
|
||||
const isFavorite = favorites.some(
|
||||
(favorite) => favorite.recordId === view.id && favorite.workspaceMemberId,
|
||||
);
|
||||
|
||||
const handleDelete = () => {
|
||||
setViewPickerReferenceViewId(view.id);
|
||||
deleteViewFromCurrentState();
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
const handleAddToFavorites = () => {
|
||||
if (!isFavorite) {
|
||||
createFavorite(view, 'view');
|
||||
}
|
||||
setViewPickerReferenceViewId(view.id);
|
||||
setViewPickerMode('favorite-folders-picker');
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItemWithOptionDropdown
|
||||
text={view.name}
|
||||
LeftIcon={getIcon(view.icon)}
|
||||
onClick={() => handleViewSelect(view.id)}
|
||||
isIconDisplayedOnHoverOnly={!isIndexView}
|
||||
RightIcon={!isHovered && isIndexView ? IconLock : null}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => {
|
||||
setIsHovered(false);
|
||||
closeDropdown();
|
||||
}}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownId={`view-picker-options-${view.id}`}
|
||||
dropdownContent={
|
||||
<DropdownMenuItemsContainer>
|
||||
{isIndexView ? (
|
||||
isFavoriteFolderEnabled && (
|
||||
<MenuItem
|
||||
LeftIcon={IconHeart}
|
||||
text={isFavorite ? 'Manage favorite' : 'Add to Favorite'}
|
||||
onClick={handleAddToFavorites}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{isFavoriteFolderEnabled && (
|
||||
<MenuItem
|
||||
LeftIcon={IconHeart}
|
||||
text={isFavorite ? 'Manage favorite' : 'Add to Favorite'}
|
||||
onClick={handleAddToFavorites}
|
||||
/>
|
||||
)}
|
||||
<MenuItem
|
||||
LeftIcon={IconPencil}
|
||||
text="Edit"
|
||||
onClick={(event) => {
|
||||
onEdit(event, view.id);
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
<MenuItem
|
||||
LeftIcon={IconTrash}
|
||||
text="Delete"
|
||||
onClick={handleDelete}
|
||||
accent="danger"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItemsContainer>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -2,4 +2,5 @@ export type ViewPickerMode =
|
||||
| 'list'
|
||||
| 'edit'
|
||||
| 'create-empty'
|
||||
| 'create-from-current';
|
||||
| 'create-from-current'
|
||||
| 'favorite-folders-picker';
|
||||
|
||||
Reference in New Issue
Block a user