Refactored dropdown content and fixed all dropdown width bugs (#12334)
This PR refactors all the dropdown content wrapping mechanism across the entire app. It refactors the internals of the `Dropdown` component and introduces a new generic `DropdownContent` component that is a generic wrapper used for each dropdown. ## Why this PR ? Because we’ve been experiencing continuous regressions for months on the dropdown content width, with weird scrolling behaviors in some and not in others, and every time a solution was found for a particular set of dropdowns, it broke another set of dropdowns, which wasn’t noticed because doing the QA of all dropdowns of the app is very difficult for fixing an apparently small bug. ## Don’t we already have a `DropdownMenu` component ? Indeed, this new `DropdownContent` is almost like `DropdownMenu` and took inspiration from it but `DropdownContent` acts as a generic content container that sets the width of the whole dropdown, whether we have a menu or not. ## Why don’t we put it directly in Dropdown internals ? Because the Dropdown component is using a complex logic with floating-ui middleware to compute its position and size, and for this logic to work correctly, it cannot be responsible for the “wanted” width of its content, because the children components, which the dropdown is not aware of, can request different widths after the dropdown has been mounted. A good example with multiple use cases inside the same dropdown can be found in `AdvancedFilterDropdownFilterInput` Thus, it is the responsibility of the content of the dropdown to determine the width it wants to have. ## What is the difference with DropdownMenuItemsContainer ? We can have multiple `DropdownMenuItemsContainer` in a dropdown, alongside other components like `DropdownMenuSeparator` or `DropdownMenuHeader`, and each of those components behaves differently regarding to its width, paddings, etc. Therefore it is logical that the `DropdownMenuItemsContainer` cannot be responsible for the whole dropdown content width, and trying to do so has been the cause of many regressions for months. Now `DropdownMenuItemsContainer` is taking a width of `auto` by default, which is the best to adapt to a parent which has a defined width. ## How do I set the width of my dropdown now ? By passing a pixel width to the props `widthInPixels` of `DropdownContent`, which only accepts numbers to avoid any confusion with `auto` , `100%` or `160px` and other specific width variables. The `dropdownWidth` props has been removed from `<Dropdown>` to avoid any confusion. Also the `DropdownMenuItemsContainer` is now using `auto` as its default width to fill the available space inside `DropdownContent` . It is highly recommended to use the enum `GenericDropdownContentWidt` to define your width. ## Where to use this new `DropdownContent` component ? There are two main use cases. If the dropdown content is defined directly inline in the Dropdown props, then it is recommended to use it here too. On the other hand if the dropdown content is abstracted in another component, it’s recommended to use this new component alongside the others components like `DropdownMenuItemsContainer`. A good rule of thumb is to place `DropdownContent` where `DropdownMenuItemsContainer`, `DropdownMenuSearchInput`, etc. are placed. ## What if I have a custom width ? Just define a constant like `ICON_PICKER_DROPDOWN_CONTENT_WIDTH` and use it with the props `widthInPixels` . Otherwise there’s a `GenericDropdownContentWidth` enum. The default value being `GenericDropdownContentWidth.Medium` (or 200px), which most dropdowns use. ## QA Component | Comment -- | -- AttachmentDropdown | Fixed overflowing (thanks to DropdownContent) RecordIndexActionMenuDropdown | CommandMenuActionMenuDropdown | SupportDropdown | Fixed overflowing (thanks to DropdownContent) MessageThreadSubscribersDropdownButton | Removed because unused FavoriteFolderNavigationDrawerItemDropdown | Set width at Narrow FavoriteFolderPicker | ViewPickerOptionDropdown | PageFavoriteFolderDropdown | Removed because unused AdvancedFilterAddFilterRuleSelect | AdvancedFilterAddFilterRuleSelect | AdvancedFilterFieldSelectMenu | AdvancedFilterRecordFilterGroupOptionsDropdown | AdvancedFilterRecordFilterOperanceSelect | Set width at Narrow AdvancedFilterLogicalOperatorDropdown | Set width at Narrow AdvancedFilterRecordFilterOptionsDropdown | AdvancedFilterRootRecordFilterGroup | Fixed broken horizontal scrolling behavior AdvancedFilterSubFieldSelectMenu | AdvancedFilterDropdownFilterInput | ObjectFilterDropdownBooleanSelect | ObjectFilterDropdownCountrySelect | Fixed broken menu items container ObjectFilterDropdownCurrencySelect | Set width to Large ObjectFilterDropdownFilterInput | ObjectFilterDropdownOperandDropdown | Fixed width that was not fixed ObjectFilterDropdownFilterInput | Fixed width that wasn’t the same for EditableFilterChip ObjectFilterDropdownOperandSelect | Refactored ObjectOptionsDropdownRecordGroupFieldsContent | Added missing separator ObjectOptionDropdownFieldsContent | ObjectOptionsDropdownHiddenFieldsContent | ObjectOptionsDropdownLayoutContent | ObjectOptionsDropdownLayoutOpenInContent | ObjectOptionsDropdownMenuContent | ObjectOptionsDropdownRecordGroupFieldsContent | ObjectOptionsDropdownRecordGroupsContent | ObjectOptionsDropdownRecordGroupSortContent | ObjectOptionsDropdownHiddenRecordGroupsContent | Removed unnecessary DropdownMenuItemsContainer RecordBoardColumnHeaderAggregateDropdown | Fixed overflowing (thanks to DropdownContent) RecordBoardColumnHeaderAggregateDropdownFieldsContent | Fixed overflowing (thanks to DropdownContent) RecordBoardColumnHeaderAggregateDropdownMenuContent | Fixed overflowing (thanks to DropdownContent) RecordBoardColumnHeaderAggregateDropdownOptionsContent | Fixed overflowing (thanks to DropdownContent) MultiItemFieldInput | Fixed overflowing (thanks to DropdownContent) MultiItemFieldMenuItem | MultipleRecordPicker | Fixed overflowing (thanks to DropdownContent) SingleRecordPicker | RecordTableColumnAggregateDropdownSubmenuContent | RecordTableColumnAggregateFooterMenuContent | RecordTableColumnHeadDropdownMenu | Fixed overflowing (thanks to DropdownContent) RecordTableHeaderPlusButtonContent | MultipleSelectDropdown | Broken width fixed ObjectSortDropdownButton | RecordDetailRelationRecordsListItem | ConfigVariableDatabaseInput | ConfigVariableOptionsDropdownContent | SettingsObjectFieldActiveActionDropdown | Fixed overflowing (thanks to DropdownContent) SettingsObjectFieldDisabledActionDropdown | Set width at Narrow SettingsObjectSummaryCard | Removed because unused SettingsDataModelFieldSelectFormOptionRow | SettingsDataModelNewFieldBreadcrumbDropdown | SettingsObjectInactiveMenuDropDown | SettingsRoleAssignementWorkspaceMemberPickerDropdown | SettingsRolePermissionObjectLevelObjectPickerDropdownContent | SettingsSecurityApprovedAccessDomainRowDropdownMenu | Couldn’t test SettingsSecuritySSORowDropdownMenu | Couldn’t test SettingsAccountsRowDropdownMenu | Fixed overflowing (thanks to DropdownContent) SettingsIntegrationDatabaseConnectionSummaryCard | Couldn’t test SettingsServerlessFunctionTablEnvironmentVariableTableRow | Deactivated scope MatchColumnSelectFieldSelectDropdownContent | Removed now unnecessary width on DropdownMenuItemsContainer MatchColumnSelectSubFieldSelectDropdownContent | SubMatchingSelectInput | CurrencyPickerDropdownSelect | IconPicker | Fixed overflowing (thanks to DropdownContent) PhoneCountryPickerDropdownSelect | Select | Refactored to drilldown wanted width of content, in this case it’s intended ExpandedListDropdown | ShowPageAddButton | Removed because unused MultiWorkspaceDropdownDefaultComponent | MultiWorkspaceDropdownThemesComponent | MultiWorkspaceDropdownWorkspacesListComponent | AdvancedFilterDropdownButton | EditableFilterChip | EditableFilterDropdownButton | UpdateViewButtonGroup | ViewBarFilterDropdown | ViewBarFilterDropdownFieldSelectMenu | ViewPickerContentCreateMode | ViewPickerContentEditMode | ViewPickerListContent | WorkflowEditTriggerDatabaseEventForm | WorkflowVariablesDropdownFieldItems | WorkflowVariablesDropdownObjectItems | WorkflowVariablesDropdownWorkflowStepItems | CommandMenuContextChipGroups | RecordBoardColumnDropdownMenu | MultiSelectInput | SelectInput | CustomSlashMenu | DropdownMenu | Removed and replaced by DropdownContent OverlayContainer and around | <!-- notionvc: 1e23bdb8-2dda-4f8d-a64d-ecc829a768a2 --> ## Miscellaneous Side notes : - The `Select` component is now wrapping the `DropdownContent` because it computes a dynamic width. - The advanced filter dropdown has been fixed, it was broken when resizing the window horizontally, we couldn’t scroll. This specific edge case was taken into account when refactoring the whole dropdown content system - As discussed with Nitin, data-select-disable will probably be removed entirely, so I let it as is, because right now it is not used by the refactored d&d selection. - Duplicate separators under DropdownMenuHeader have been removed. Fixes : https://github.com/twentyhq/twenty/issues/12327 Fixes : https://github.com/twentyhq/core-team-issues/issues/951
This commit is contained in:
@ -5,6 +5,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
|||||||
import { CommandMenuActionMenuDropdownHotkeyScope } from '@/action-menu/types/CommandMenuActionMenuDropdownHotkeyScope';
|
import { CommandMenuActionMenuDropdownHotkeyScope } from '@/action-menu/types/CommandMenuActionMenuDropdownHotkeyScope';
|
||||||
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
@ -72,19 +73,21 @@ export const CommandMenuActionMenuDropdown = () => {
|
|||||||
setSelectedItemId(selectableItemIdArray[0]);
|
setSelectedItemId(selectableItemIdArray[0]);
|
||||||
}}
|
}}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<SelectableList
|
<DropdownMenuItemsContainer>
|
||||||
selectableListInstanceId={actionMenuId}
|
<SelectableList
|
||||||
hotkeyScope={
|
selectableListInstanceId={actionMenuId}
|
||||||
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown
|
hotkeyScope={
|
||||||
}
|
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown
|
||||||
selectableItemIdArray={selectableItemIdArray}
|
}
|
||||||
>
|
selectableItemIdArray={selectableItemIdArray}
|
||||||
{recordSelectionActions.map((action) => (
|
>
|
||||||
<ActionComponent action={action} key={action.key} />
|
{recordSelectionActions.map((action) => (
|
||||||
))}
|
<ActionComponent action={action} key={action.key} />
|
||||||
</SelectableList>
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</SelectableList>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDro
|
|||||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
@ -82,39 +83,41 @@ export const RecordIndexActionMenuDropdown = () => {
|
|||||||
y: actionMenuDropdownPosition.y ?? 0,
|
y: actionMenuDropdownPosition.y ?? 0,
|
||||||
}}
|
}}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<StyledDropdownMenuContainer
|
<DropdownContent>
|
||||||
data-click-outside-id={ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID}
|
<StyledDropdownMenuContainer
|
||||||
>
|
data-click-outside-id={ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID}
|
||||||
<DropdownMenuItemsContainer>
|
>
|
||||||
<SelectableList
|
<DropdownMenuItemsContainer>
|
||||||
hotkeyScope={ActionMenuDropdownHotkeyScope.ActionMenuDropdown}
|
<SelectableList
|
||||||
selectableItemIdArray={selectedItemIdArray}
|
hotkeyScope={ActionMenuDropdownHotkeyScope.ActionMenuDropdown}
|
||||||
selectableListInstanceId={dropdownId}
|
selectableItemIdArray={selectedItemIdArray}
|
||||||
>
|
selectableListInstanceId={dropdownId}
|
||||||
{recordIndexActions.map((action) => (
|
|
||||||
<ActionComponent action={action} key={action.key} />
|
|
||||||
))}
|
|
||||||
<SelectableListItem
|
|
||||||
itemId="more-actions"
|
|
||||||
key="more-actions"
|
|
||||||
onEnter={() => {
|
|
||||||
closeDropdown(dropdownId);
|
|
||||||
openCommandMenu();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<MenuItem
|
{recordIndexActions.map((action) => (
|
||||||
LeftIcon={IconLayoutSidebarRightExpand}
|
<ActionComponent action={action} key={action.key} />
|
||||||
onClick={() => {
|
))}
|
||||||
|
<SelectableListItem
|
||||||
|
itemId="more-actions"
|
||||||
|
key="more-actions"
|
||||||
|
onEnter={() => {
|
||||||
closeDropdown(dropdownId);
|
closeDropdown(dropdownId);
|
||||||
openCommandMenu();
|
openCommandMenu();
|
||||||
}}
|
}}
|
||||||
focused={selectedItemId === 'more-actions'}
|
>
|
||||||
text="More actions"
|
<MenuItem
|
||||||
/>
|
LeftIcon={IconLayoutSidebarRightExpand}
|
||||||
</SelectableListItem>
|
onClick={() => {
|
||||||
</SelectableList>
|
closeDropdown(dropdownId);
|
||||||
</DropdownMenuItemsContainer>
|
openCommandMenu();
|
||||||
</StyledDropdownMenuContainer>
|
}}
|
||||||
|
focused={selectedItemId === 'more-actions'}
|
||||||
|
text="More actions"
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
</SelectableList>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</StyledDropdownMenuContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
import { MessageThreadSubscribersDropdownButton } from '@/activities/emails/components/MessageThreadSubscribersDropdownButton';
|
|
||||||
import { MessageThread } from '@/activities/emails/types/MessageThread';
|
|
||||||
|
|
||||||
export const EmailThreadMembersChip = ({
|
|
||||||
messageThread,
|
|
||||||
}: {
|
|
||||||
messageThread: MessageThread;
|
|
||||||
}) => {
|
|
||||||
const subscribers = messageThread.subscribers ?? [];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MessageThreadSubscribersDropdownButton
|
|
||||||
messageThreadSubscribers={subscribers}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
import { MessageThreadSubscriber } from '@/activities/emails/types/MessageThreadSubscriber';
|
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Chip, ChipVariant } from 'twenty-ui/components';
|
|
||||||
import { Avatar, AvatarGroup, IconChevronDown } from 'twenty-ui/display';
|
|
||||||
import { ThemeContext } from 'twenty-ui/theme';
|
|
||||||
|
|
||||||
const MAX_NUMBER_OF_AVATARS = 3;
|
|
||||||
|
|
||||||
export const MessageThreadSubscribersChip = ({
|
|
||||||
messageThreadSubscribers,
|
|
||||||
}: {
|
|
||||||
messageThreadSubscribers: MessageThreadSubscriber[];
|
|
||||||
}) => {
|
|
||||||
const { theme } = useContext(ThemeContext);
|
|
||||||
|
|
||||||
const numberOfMessageThreadSubscribers = messageThreadSubscribers.length;
|
|
||||||
|
|
||||||
const isOnlyOneSubscriber = numberOfMessageThreadSubscribers === 1;
|
|
||||||
|
|
||||||
const isPrivateThread = isOnlyOneSubscriber;
|
|
||||||
|
|
||||||
const privateLabel = 'Private';
|
|
||||||
|
|
||||||
const susbcriberAvatarUrls = messageThreadSubscribers
|
|
||||||
.map((member) => member.workspaceMember.avatarUrl)
|
|
||||||
.filter(isNonEmptyString);
|
|
||||||
|
|
||||||
const firstAvatarUrl = susbcriberAvatarUrls[0];
|
|
||||||
const firstAvatarColorSeed = messageThreadSubscribers?.[0].workspaceMember.id;
|
|
||||||
const firstAvatarPlaceholder =
|
|
||||||
messageThreadSubscribers?.[0].workspaceMember.name.firstName;
|
|
||||||
|
|
||||||
const subscriberNames = messageThreadSubscribers.map(
|
|
||||||
(member) => member.workspaceMember?.name.firstName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const moreAvatarsLabel =
|
|
||||||
numberOfMessageThreadSubscribers > MAX_NUMBER_OF_AVATARS
|
|
||||||
? `+${numberOfMessageThreadSubscribers - MAX_NUMBER_OF_AVATARS}`
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const label = isPrivateThread ? privateLabel : (moreAvatarsLabel ?? '');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Chip
|
|
||||||
label={label}
|
|
||||||
variant={ChipVariant.Highlighted}
|
|
||||||
leftComponent={
|
|
||||||
isOnlyOneSubscriber ? (
|
|
||||||
<Avatar
|
|
||||||
avatarUrl={firstAvatarUrl}
|
|
||||||
placeholderColorSeed={firstAvatarColorSeed}
|
|
||||||
placeholder={firstAvatarPlaceholder}
|
|
||||||
size="md"
|
|
||||||
type={'rounded'}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<AvatarGroup
|
|
||||||
avatars={subscriberNames.map((name, index) => (
|
|
||||||
<Avatar
|
|
||||||
key={name}
|
|
||||||
avatarUrl={susbcriberAvatarUrls[index] ?? ''}
|
|
||||||
placeholder={name}
|
|
||||||
type="rounded"
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
rightComponent={() => <IconChevronDown size={theme.icon.size.sm} />}
|
|
||||||
clickable
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
import { offset } from '@floating-ui/react';
|
|
||||||
|
|
||||||
import { MessageThreadSubscriberDropdownAddSubscriber } from '@/activities/emails/components/MessageThreadSubscriberDropdownAddSubscriber';
|
|
||||||
import { MessageThreadSubscribersChip } from '@/activities/emails/components/MessageThreadSubscribersChip';
|
|
||||||
import { MessageThreadSubscriber } from '@/activities/emails/types/MessageThreadSubscriber';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
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 { useListenRightDrawerClose } from '@/ui/layout/right-drawer/hooks/useListenRightDrawerClose';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { IconMinus, IconPlus } from 'twenty-ui/display';
|
|
||||||
import { MenuItem, MenuItemAvatar } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
export const MESSAGE_THREAD_SUBSCRIBER_DROPDOWN_ID =
|
|
||||||
'message-thread-subscriber';
|
|
||||||
|
|
||||||
export const MessageThreadSubscribersDropdownButton = ({
|
|
||||||
messageThreadSubscribers,
|
|
||||||
}: {
|
|
||||||
messageThreadSubscribers: MessageThreadSubscriber[];
|
|
||||||
}) => {
|
|
||||||
const [isAddingSubscriber, setIsAddingSubscriber] = useState(false);
|
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(MESSAGE_THREAD_SUBSCRIBER_DROPDOWN_ID);
|
|
||||||
|
|
||||||
const mockSubscribers = [
|
|
||||||
...messageThreadSubscribers,
|
|
||||||
...messageThreadSubscribers,
|
|
||||||
...messageThreadSubscribers,
|
|
||||||
...messageThreadSubscribers,
|
|
||||||
];
|
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
const handleAddSubscriberClick = () => {
|
|
||||||
setIsAddingSubscriber(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
const handleRemoveSubscriber = (_subscriber: MessageThreadSubscriber) => {
|
|
||||||
closeDropdown();
|
|
||||||
};
|
|
||||||
|
|
||||||
useListenRightDrawerClose(() => {
|
|
||||||
closeDropdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
dropdownId={MESSAGE_THREAD_SUBSCRIBER_DROPDOWN_ID}
|
|
||||||
clickableComponent={
|
|
||||||
<MessageThreadSubscribersChip
|
|
||||||
messageThreadSubscribers={mockSubscribers}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
dropdownComponents={
|
|
||||||
<DropdownMenu width="160px" z-index={offset(1)}>
|
|
||||||
{isAddingSubscriber ? (
|
|
||||||
<MessageThreadSubscriberDropdownAddSubscriber
|
|
||||||
existingSubscribers={messageThreadSubscribers}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
{messageThreadSubscribers?.map((subscriber) => (
|
|
||||||
<MenuItemAvatar
|
|
||||||
key={subscriber.workspaceMember.id}
|
|
||||||
testId="menu-item"
|
|
||||||
onClick={() => {
|
|
||||||
handleRemoveSubscriber(subscriber);
|
|
||||||
}}
|
|
||||||
text={
|
|
||||||
subscriber.workspaceMember.name.firstName +
|
|
||||||
' ' +
|
|
||||||
subscriber.workspaceMember.name.lastName
|
|
||||||
}
|
|
||||||
avatar={{
|
|
||||||
placeholder: subscriber.workspaceMember.name.firstName,
|
|
||||||
avatarUrl: subscriber.workspaceMember.avatarUrl,
|
|
||||||
placeholderColorSeed: subscriber.workspaceMember.id,
|
|
||||||
size: 'md',
|
|
||||||
type: 'rounded',
|
|
||||||
}}
|
|
||||||
iconButtons={[
|
|
||||||
{
|
|
||||||
Icon: IconMinus,
|
|
||||||
onClick: () => {
|
|
||||||
handleRemoveSubscriber(subscriber);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<MenuItem
|
|
||||||
LeftIcon={IconPlus}
|
|
||||||
onClick={handleAddSubscriberClick}
|
|
||||||
text="Add subscriber"
|
|
||||||
/>
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
)}
|
|
||||||
</DropdownMenu>
|
|
||||||
}
|
|
||||||
dropdownHotkeyScope={{ scope: MESSAGE_THREAD_SUBSCRIBER_DROPDOWN_ID }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,5 +1,7 @@
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import {
|
import {
|
||||||
IconDotsVertical,
|
IconDotsVertical,
|
||||||
@ -48,26 +50,27 @@ export const AttachmentDropdown = ({
|
|||||||
clickableComponent={
|
clickableComponent={
|
||||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text="Download"
|
<MenuItem
|
||||||
LeftIcon={IconDownload}
|
text="Download"
|
||||||
onClick={handleDownload}
|
LeftIcon={IconDownload}
|
||||||
/>
|
onClick={handleDownload}
|
||||||
<MenuItem
|
/>
|
||||||
text="Rename"
|
<MenuItem
|
||||||
LeftIcon={IconPencil}
|
text="Rename"
|
||||||
onClick={handleRename}
|
LeftIcon={IconPencil}
|
||||||
/>
|
onClick={handleRename}
|
||||||
<MenuItem
|
/>
|
||||||
text="Delete"
|
<MenuItem
|
||||||
accent="danger"
|
text="Delete"
|
||||||
LeftIcon={IconTrash}
|
accent="danger"
|
||||||
onClick={handleDelete}
|
LeftIcon={IconTrash}
|
||||||
/>
|
onClick={handleDelete}
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -4,11 +4,11 @@ import { SubTitle } from '@/auth/components/SubTitle';
|
|||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { useHandleResendEmailVerificationToken } from '@/auth/sign-in-up/hooks/useHandleResendEmailVerificationToken';
|
import { useHandleResendEmailVerificationToken } from '@/auth/sign-in-up/hooks/useHandleResendEmailVerificationToken';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import { AnimatedEaseIn } from 'twenty-ui/utilities';
|
|
||||||
import { IconMail } from 'twenty-ui/display';
|
import { IconMail } from 'twenty-ui/display';
|
||||||
import { Loader } from 'twenty-ui/feedback';
|
import { Loader } from 'twenty-ui/feedback';
|
||||||
import { MainButton } from 'twenty-ui/input';
|
import { MainButton } from 'twenty-ui/input';
|
||||||
import { RGBA } from 'twenty-ui/theme';
|
import { RGBA } from 'twenty-ui/theme';
|
||||||
|
import { AnimatedEaseIn } from 'twenty-ui/utilities';
|
||||||
|
|
||||||
const StyledMailContainer = styled.div`
|
const StyledMailContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
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 { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
import {
|
import {
|
||||||
CommandMenuContextChip,
|
CommandMenuContextChip,
|
||||||
CommandMenuContextChipProps,
|
CommandMenuContextChipProps,
|
||||||
} from './CommandMenuContextChip';
|
} from './CommandMenuContextChip';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
export const CommandMenuContextChipGroups = ({
|
export const CommandMenuContextChipGroups = ({
|
||||||
contextChips,
|
contextChips,
|
||||||
@ -53,19 +54,23 @@ export const CommandMenuContextChipGroups = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
{firstChips.map((chip, index) => (
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItem
|
{firstChips.map((chip, index) => (
|
||||||
key={index}
|
<MenuItem
|
||||||
LeftComponent={chip.Icons}
|
key={index}
|
||||||
text={chip.text}
|
LeftComponent={chip.Icons}
|
||||||
onClick={() => {
|
text={chip.text}
|
||||||
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
|
onClick={() => {
|
||||||
chip.onClick?.();
|
closeDropdown(
|
||||||
}}
|
COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID,
|
||||||
/>
|
);
|
||||||
))}
|
chip.onClick?.();
|
||||||
</DropdownMenuItemsContainer>
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{
|
dropdownHotkeyScope={{
|
||||||
scope: AppHotkeyScope.CommandMenu,
|
scope: AppHotkeyScope.CommandMenu,
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { FavoriteFolderHotkeyScope } from '@/favorites/constants/FavoriteFolderRightIconDropdownHotkeyScope';
|
import { FavoriteFolderHotkeyScope } from '@/favorites/constants/FavoriteFolderRightIconDropdownHotkeyScope';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { IconDotsVertical, IconPencil, IconTrash } from 'twenty-ui/display';
|
import { IconDotsVertical, IconPencil, IconTrash } from 'twenty-ui/display';
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
@ -40,20 +42,22 @@ export const FavoriteFolderNavigationDrawerItemDropdown = ({
|
|||||||
}
|
}
|
||||||
dropdownPlacement="bottom-start"
|
dropdownPlacement="bottom-start"
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
LeftIcon={IconPencil}
|
<MenuItem
|
||||||
onClick={handleRename}
|
LeftIcon={IconPencil}
|
||||||
accent="default"
|
onClick={handleRename}
|
||||||
text="Rename"
|
accent="default"
|
||||||
/>
|
text="Rename"
|
||||||
<MenuItem
|
/>
|
||||||
LeftIcon={IconTrash}
|
<MenuItem
|
||||||
onClick={handleDelete}
|
LeftIcon={IconTrash}
|
||||||
accent="danger"
|
onClick={handleDelete}
|
||||||
text="Delete"
|
accent="danger"
|
||||||
/>
|
text="Delete"
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,50 +0,0 @@
|
|||||||
import { PageFavoriteButton } from '@/favorites/components/PageFavoriteButton';
|
|
||||||
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 { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|
||||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
|
||||||
|
|
||||||
type PageFavoriteFoldersDropdownProps = {
|
|
||||||
dropdownId: string;
|
|
||||||
isFavorite: boolean;
|
|
||||||
record?: ObjectRecord;
|
|
||||||
objectNameSingular: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PageFavoriteFoldersDropdown = ({
|
|
||||||
dropdownId,
|
|
||||||
isFavorite,
|
|
||||||
record,
|
|
||||||
objectNameSingular,
|
|
||||||
}: PageFavoriteFoldersDropdownProps) => {
|
|
||||||
const { closeDropdown } = useDropdown(dropdownId);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FavoriteFolderPickerComponentInstanceContext
|
|
||||||
favoriteFoldersScopeId={dropdownId}
|
|
||||||
>
|
|
||||||
<DropdownScope dropdownScopeId={dropdownId}>
|
|
||||||
<Dropdown
|
|
||||||
dropdownId={dropdownId}
|
|
||||||
dropdownPlacement="bottom-start"
|
|
||||||
clickableComponent={<PageFavoriteButton isFavorite={isFavorite} />}
|
|
||||||
dropdownComponents={
|
|
||||||
<>
|
|
||||||
<FavoriteFolderPickerEffect record={record} />
|
|
||||||
<FavoriteFolderPicker
|
|
||||||
onSubmit={closeDropdown}
|
|
||||||
record={record}
|
|
||||||
objectNameSingular={objectNameSingular}
|
|
||||||
dropdownId={dropdownId}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
|
||||||
/>
|
|
||||||
</DropdownScope>
|
|
||||||
</FavoriteFolderPickerComponentInstanceContext>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -6,7 +6,7 @@ import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder
|
|||||||
import { favoriteFolderSearchFilterComponentState } from '@/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState';
|
import { favoriteFolderSearchFilterComponentState } from '@/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState';
|
||||||
import { isFavoriteFolderCreatingState } from '@/favorites/states/isFavoriteFolderCreatingState';
|
import { isFavoriteFolderCreatingState } from '@/favorites/states/isFavoriteFolderCreatingState';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
@ -90,7 +90,7 @@ export const FavoriteFolderPicker = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu data-select-disable>
|
<DropdownContent>
|
||||||
<FavoriteFolderPickerSearchInput />
|
<FavoriteFolderPickerSearchInput />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItemsContainer hasMaxHeight>
|
<DropdownMenuItemsContainer hasMaxHeight>
|
||||||
@ -101,6 +101,6 @@ export const FavoriteFolderPicker = ({
|
|||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<FavoriteFolderPickerFooter dropdownId={dropdownId} />
|
<FavoriteFolderPickerFooter dropdownId={dropdownId} />
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
|||||||
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||||
@ -151,20 +152,22 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
<LightButton Icon={IconPlus} title="Add filter rule" />
|
<LightButton Icon={IconPlus} title="Add filter rule" />
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
LeftIcon={IconPlus}
|
|
||||||
text="Add rule"
|
|
||||||
onClick={handleAddFilter}
|
|
||||||
/>
|
|
||||||
{isFilterRuleGroupOptionVisible && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
LeftIcon={IconLibraryPlus}
|
LeftIcon={IconPlus}
|
||||||
text="Add rule group"
|
text="Add rule"
|
||||||
onClick={handleAddFilterGroup}
|
onClick={handleAddFilter}
|
||||||
/>
|
/>
|
||||||
)}
|
{isFilterRuleGroupOptionVisible && (
|
||||||
</DropdownMenuItemsContainer>
|
<MenuItem
|
||||||
|
LeftIcon={IconLibraryPlus}
|
||||||
|
text="Add rule group"
|
||||||
|
onClick={handleAddFilterGroup}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
dropdownOffset={{ y: 8, x: 0 }}
|
dropdownOffset={{ y: 8, x: 0 }}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object
|
|||||||
import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
||||||
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
|
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
|
|
||||||
@ -52,28 +53,24 @@ export const AdvancedFilterDropdownFilterInput = ({
|
|||||||
<ObjectFilterDropdownDateInput />
|
<ObjectFilterDropdownDateInput />
|
||||||
)}
|
)}
|
||||||
{filterType === 'RELATION' && (
|
{filterType === 'RELATION' && (
|
||||||
<>
|
<DropdownContent>
|
||||||
<ObjectFilterDropdownSearchInput />
|
<ObjectFilterDropdownSearchInput />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ObjectFilterDropdownRecordSelect recordFilterId={recordFilter.id} />
|
<ObjectFilterDropdownRecordSelect recordFilterId={recordFilter.id} />
|
||||||
</>
|
</DropdownContent>
|
||||||
)}
|
)}
|
||||||
{filterType === 'ACTOR' &&
|
{filterType === 'ACTOR' &&
|
||||||
(isActorSourceCompositeFilter ? (
|
(isActorSourceCompositeFilter ? (
|
||||||
<>
|
<ObjectFilterDropdownSourceSelect />
|
||||||
<ObjectFilterDropdownSourceSelect />
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<ObjectFilterDropdownTextInput />
|
||||||
<ObjectFilterDropdownTextInput />
|
|
||||||
</>
|
|
||||||
))}
|
))}
|
||||||
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
||||||
<>
|
<DropdownContent>
|
||||||
<ObjectFilterDropdownSearchInput />
|
<ObjectFilterDropdownSearchInput />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ObjectFilterDropdownOptionSelect />
|
<ObjectFilterDropdownOptionSelect />
|
||||||
</>
|
</DropdownContent>
|
||||||
)}
|
)}
|
||||||
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||||
{filterType === 'CURRENCY' &&
|
{filterType === 'CURRENCY' &&
|
||||||
@ -82,9 +79,7 @@ export const AdvancedFilterDropdownFilterInput = ({
|
|||||||
'currencyCode',
|
'currencyCode',
|
||||||
recordFilter.subFieldName,
|
recordFilter.subFieldName,
|
||||||
) ? (
|
) ? (
|
||||||
<>
|
<ObjectFilterDropdownCurrencySelect />
|
||||||
<ObjectFilterDropdownCurrencySelect />
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/o
|
|||||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ export const AdvancedFilterFieldSelectMenu = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<AdvancedFilterFieldSelectSearchInput />
|
<AdvancedFilterFieldSelectSearchInput />
|
||||||
<SelectableList
|
<SelectableList
|
||||||
hotkeyScope={advancedFilterFieldSelectDropdownId}
|
hotkeyScope={advancedFilterFieldSelectDropdownId}
|
||||||
@ -175,6 +176,6 @@ export const AdvancedFilterFieldSelectMenu = ({
|
|||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/
|
|||||||
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
import { Select } from '@/ui/input/components/Select';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
|
|
||||||
type AdvancedFilterLogicalOperatorDropdownProps = {
|
type AdvancedFilterLogicalOperatorDropdownProps = {
|
||||||
recordFilterGroup: RecordFilterGroup;
|
recordFilterGroup: RecordFilterGroup;
|
||||||
@ -27,6 +28,7 @@ export const AdvancedFilterLogicalOperatorDropdown = ({
|
|||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
fullWidth
|
fullWidth
|
||||||
|
dropdownWidth={GenericDropdownContentWidth.Narrow}
|
||||||
dropdownId={`advanced-filter-logical-operator-${recordFilterGroup.id}`}
|
dropdownId={`advanced-filter-logical-operator-${recordFilterGroup.id}`}
|
||||||
value={recordFilterGroup.logicalOperator}
|
value={recordFilterGroup.logicalOperator}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@ -4,10 +4,11 @@ import { useRemoveRootRecordFilterGroupIfEmpty } from '@/object-record/record-fi
|
|||||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||||
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { IconButton } from 'twenty-ui/input';
|
|
||||||
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||||
|
import { IconButton } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
type AdvancedFilterRecordFilterGroupOptionsDropdownProps = {
|
type AdvancedFilterRecordFilterGroupOptionsDropdownProps = {
|
||||||
@ -53,14 +54,16 @@ export const AdvancedFilterRecordFilterGroupOptionsDropdown = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text="Remove rule group"
|
<MenuItem
|
||||||
onClick={handleRemove}
|
text="Remove rule group"
|
||||||
LeftIcon={IconTrash}
|
onClick={handleRemove}
|
||||||
accent="danger"
|
LeftIcon={IconTrash}
|
||||||
/>
|
accent="danger"
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
dropdownOffset={{ y: 2, x: 0 }}
|
dropdownOffset={{ y: 2, x: 0 }}
|
||||||
|
|||||||
@ -6,7 +6,9 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
|||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||||
@ -94,38 +96,39 @@ export const AdvancedFilterRecordFilterOperandSelect = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer width="auto">
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<SelectableList
|
<DropdownMenuItemsContainer>
|
||||||
hotkeyScope={dropdownId}
|
<SelectableList
|
||||||
selectableItemIdArray={operandsForFilterType.map(
|
hotkeyScope={dropdownId}
|
||||||
(operand) => operand,
|
selectableItemIdArray={operandsForFilterType.map(
|
||||||
)}
|
(operand) => operand,
|
||||||
selectableListInstanceId={dropdownId}
|
)}
|
||||||
>
|
selectableListInstanceId={dropdownId}
|
||||||
{operandsForFilterType.map((filterOperand, index) => (
|
>
|
||||||
<SelectableListItem
|
{operandsForFilterType.map((filterOperand, index) => (
|
||||||
itemId={filterOperand}
|
<SelectableListItem
|
||||||
key={`select-filter-operand-${index}`}
|
itemId={filterOperand}
|
||||||
onEnter={() => {
|
key={`select-filter-operand-${index}`}
|
||||||
handleOperandChange(filterOperand);
|
onEnter={() => {
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
focused={selectedItemId === filterOperand}
|
|
||||||
onClick={() => {
|
|
||||||
handleOperandChange(filterOperand);
|
handleOperandChange(filterOperand);
|
||||||
}}
|
}}
|
||||||
text={getOperandLabel(filterOperand)}
|
>
|
||||||
/>
|
<MenuItem
|
||||||
</SelectableListItem>
|
focused={selectedItemId === filterOperand}
|
||||||
))}
|
onClick={() => {
|
||||||
</SelectableList>
|
handleOperandChange(filterOperand);
|
||||||
</DropdownMenuItemsContainer>
|
}}
|
||||||
|
text={getOperandLabel(filterOperand)}
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
))}
|
||||||
|
</SelectableList>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
||||||
dropdownPlacement="bottom-start"
|
dropdownPlacement="bottom-start"
|
||||||
dropdownWidth={200}
|
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,12 +7,13 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
|||||||
|
|
||||||
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconButton } from 'twenty-ui/input';
|
|
||||||
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||||
|
import { IconButton } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
type AdvancedFilterRecordFilterOptionsDropdownProps = {
|
type AdvancedFilterRecordFilterOptionsDropdownProps = {
|
||||||
@ -73,14 +74,16 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text="Remove rule"
|
<MenuItem
|
||||||
onClick={handleRemove}
|
text="Remove rule"
|
||||||
LeftIcon={IconTrash}
|
onClick={handleRemove}
|
||||||
accent="danger"
|
LeftIcon={IconTrash}
|
||||||
/>
|
accent="danger"
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
||||||
|
|||||||
@ -2,9 +2,11 @@ import { AdvancedFilterAddFilterRuleSelect } from '@/object-record/advanced-filt
|
|||||||
|
|
||||||
import { AdvancedFilterRecordFilterGroupRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupRow';
|
import { AdvancedFilterRecordFilterGroupRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupRow';
|
||||||
import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow';
|
import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow';
|
||||||
|
import { ADVANCED_FILTER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/advanced-filter/constants/AdvancedFilterDropdownContentWidth';
|
||||||
import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups';
|
import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups';
|
||||||
import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector';
|
import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector';
|
||||||
import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup';
|
import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
@ -18,7 +20,6 @@ const StyledContainer = styled.div<{ isGrayBackground?: boolean }>`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
padding: ${({ theme }) => theme.spacing(2)};
|
||||||
min-width: 650px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const AdvancedFilterRootRecordFilterGroup = () => {
|
export const AdvancedFilterRootRecordFilterGroup = () => {
|
||||||
@ -37,31 +38,33 @@ export const AdvancedFilterRootRecordFilterGroup = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollWrapper componentInstanceId={`scroll-wrapper-dropdown-menu-${id}`}>
|
<ScrollWrapper componentInstanceId={`scroll-wrapper-dropdown-menu-${id}`}>
|
||||||
<StyledContainer>
|
<DropdownContent widthInPixels={ADVANCED_FILTER_DROPDOWN_CONTENT_WIDTH}>
|
||||||
{childRecordFiltersAndRecordFilterGroups.map(
|
<StyledContainer>
|
||||||
(recordFilterGroupChild, recordFilterGroupChildIndex) =>
|
{childRecordFiltersAndRecordFilterGroups.map(
|
||||||
isRecordFilterGroupChildARecordFilterGroup(
|
(recordFilterGroupChild, recordFilterGroupChildIndex) =>
|
||||||
recordFilterGroupChild,
|
isRecordFilterGroupChildARecordFilterGroup(
|
||||||
) ? (
|
recordFilterGroupChild,
|
||||||
<AdvancedFilterRecordFilterGroupRow
|
) ? (
|
||||||
key={recordFilterGroupChild.id}
|
<AdvancedFilterRecordFilterGroupRow
|
||||||
parentRecordFilterGroup={rootRecordFilterGroup}
|
key={recordFilterGroupChild.id}
|
||||||
recordFilterGroup={recordFilterGroupChild}
|
parentRecordFilterGroup={rootRecordFilterGroup}
|
||||||
recordFilterGroupIndex={recordFilterGroupChildIndex}
|
recordFilterGroup={recordFilterGroupChild}
|
||||||
/>
|
recordFilterGroupIndex={recordFilterGroupChildIndex}
|
||||||
) : (
|
/>
|
||||||
<AdvancedFilterRecordFilterRow
|
) : (
|
||||||
key={recordFilterGroupChild.id}
|
<AdvancedFilterRecordFilterRow
|
||||||
recordFilterGroup={rootRecordFilterGroup}
|
key={recordFilterGroupChild.id}
|
||||||
recordFilter={recordFilterGroupChild}
|
recordFilterGroup={rootRecordFilterGroup}
|
||||||
recordFilterIndex={recordFilterGroupChildIndex}
|
recordFilter={recordFilterGroupChild}
|
||||||
/>
|
recordFilterIndex={recordFilterGroupChildIndex}
|
||||||
),
|
/>
|
||||||
)}
|
),
|
||||||
<AdvancedFilterAddFilterRuleSelect
|
)}
|
||||||
recordFilterGroup={rootRecordFilterGroup}
|
<AdvancedFilterAddFilterRuleSelect
|
||||||
/>
|
recordFilterGroup={rootRecordFilterGroup}
|
||||||
</StyledContainer>
|
/>
|
||||||
|
</StyledContainer>
|
||||||
|
</DropdownContent>
|
||||||
</ScrollWrapper>
|
</ScrollWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { areCompositeTypeSubFieldsFilterable } from '@/object-record/record-filt
|
|||||||
import { isCompositeTypeFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeFilterableByAnySubField';
|
import { isCompositeTypeFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeFilterableByAnySubField';
|
||||||
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
||||||
import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
@ -110,7 +111,7 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -184,6 +185,6 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
|||||||
))}
|
))}
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -133,7 +133,6 @@ export const AdvancedFilterValueInput = ({
|
|||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
dropdownOffset={dropdownContentOffset}
|
dropdownOffset={dropdownContentOffset}
|
||||||
dropdownPlacement="bottom-start"
|
dropdownPlacement="bottom-start"
|
||||||
dropdownWidth={280}
|
|
||||||
onClose={handleFilterValueDropdownClose}
|
onClose={handleFilterValueDropdownClose}
|
||||||
onOpen={handleFilterValueDropdownOpen}
|
onOpen={handleFilterValueDropdownOpen}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const ADVANCED_FILTER_DROPDOWN_CONTENT_WIDTH = 650;
|
||||||
@ -5,6 +5,7 @@ import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-
|
|||||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||||
import { BooleanDisplay } from '@/ui/field/display/components/BooleanDisplay';
|
import { BooleanDisplay } from '@/ui/field/display/components/BooleanDisplay';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
@ -51,27 +52,29 @@ export const ObjectFilterDropdownBooleanSelect = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectableList
|
<DropdownContent>
|
||||||
selectableListInstanceId="boolean-select"
|
<SelectableList
|
||||||
selectableItemIdArray={options.map((option) => option.toString())}
|
selectableListInstanceId="boolean-select"
|
||||||
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
|
selectableItemIdArray={options.map((option) => option.toString())}
|
||||||
>
|
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
|
||||||
<DropdownMenuItemsContainer hasMaxHeight width="auto">
|
>
|
||||||
{options.map((option) => (
|
<DropdownMenuItemsContainer hasMaxHeight width="auto">
|
||||||
<StyledBooleanSelectContainer
|
{options.map((option) => (
|
||||||
key={String(option)}
|
<StyledBooleanSelectContainer
|
||||||
onClick={() => handleOptionSelect(option)}
|
key={String(option)}
|
||||||
selected={objectFilterDropdownFilterValue === option.toString()}
|
onClick={() => handleOptionSelect(option)}
|
||||||
>
|
selected={objectFilterDropdownFilterValue === option.toString()}
|
||||||
<BooleanDisplay value={option} />
|
>
|
||||||
{objectFilterDropdownFilterValue === option.toString() && (
|
<BooleanDisplay value={option} />
|
||||||
<StyledIconCheckContainer>
|
{objectFilterDropdownFilterValue === option.toString() && (
|
||||||
<IconCheck color={theme.grayScale.gray50} size={16} />
|
<StyledIconCheckContainer>
|
||||||
</StyledIconCheckContainer>
|
<IconCheck color={theme.grayScale.gray50} size={16} />
|
||||||
)}
|
</StyledIconCheckContainer>
|
||||||
</StyledBooleanSelectContainer>
|
)}
|
||||||
))}
|
</StyledBooleanSelectContainer>
|
||||||
</DropdownMenuItemsContainer>
|
))}
|
||||||
</SelectableList>
|
</DropdownMenuItemsContainer>
|
||||||
|
</SelectableList>
|
||||||
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { getCountryFlagMenuItemAvatar } from '@/object-record/object-filter-drop
|
|||||||
import { turnCountryIntoSelectableItem } from '@/object-record/object-filter-dropdown/utils/turnCountryIntoSelectableItem';
|
import { turnCountryIntoSelectableItem } from '@/object-record/object-filter-dropdown/utils/turnCountryIntoSelectableItem';
|
||||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||||
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
|
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
@ -18,13 +19,7 @@ import { MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
|
|||||||
export const EMPTY_FILTER_VALUE = '[]';
|
export const EMPTY_FILTER_VALUE = '[]';
|
||||||
export const MAX_ITEMS_TO_DISPLAY = 5;
|
export const MAX_ITEMS_TO_DISPLAY = 5;
|
||||||
|
|
||||||
type ObjectFilterDropdownCountrySelectProps = {
|
export const ObjectFilterDropdownCountrySelect = () => {
|
||||||
dropdownWidth?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ObjectFilterDropdownCountrySelect = ({
|
|
||||||
dropdownWidth,
|
|
||||||
}: ObjectFilterDropdownCountrySelectProps) => {
|
|
||||||
const [searchText, setSearchText] = useState('');
|
const [searchText, setSearchText] = useState('');
|
||||||
|
|
||||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||||
@ -101,7 +96,7 @@ export const ObjectFilterDropdownCountrySelect = ({
|
|||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
autoFocus
|
autoFocus
|
||||||
type="text"
|
type="text"
|
||||||
@ -112,7 +107,7 @@ export const ObjectFilterDropdownCountrySelect = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItemsContainer hasMaxHeight width={dropdownWidth ?? 200}>
|
<DropdownMenuItemsContainer hasMaxHeight>
|
||||||
{filteredSelectedItems?.map((item) => {
|
{filteredSelectedItems?.map((item) => {
|
||||||
return (
|
return (
|
||||||
<MenuItemMultiSelectAvatar
|
<MenuItemMultiSelectAvatar
|
||||||
@ -141,6 +136,6 @@ export const ObjectFilterDropdownCountrySelect = ({
|
|||||||
})}
|
})}
|
||||||
{showNoResult && <MenuItem text={t`No results`} />}
|
{showNoResult && <MenuItem text={t`No results`} />}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,9 +5,11 @@ import { turnCurrencyIntoSelectableItem } from '@/object-record/object-filter-dr
|
|||||||
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
||||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||||
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
@ -95,7 +97,7 @@ export const ObjectFilterDropdownCurrencySelect = () => {
|
|||||||
searchText !== '';
|
searchText !== '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Large}>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
autoFocus
|
autoFocus
|
||||||
type="text"
|
type="text"
|
||||||
@ -153,6 +155,6 @@ export const ObjectFilterDropdownCurrencySelect = () => {
|
|||||||
})}
|
})}
|
||||||
{showNoResult && <MenuItem text={t`No results`} />}
|
{showNoResult && <MenuItem text={t`No results`} />}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,17 +9,16 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
|||||||
|
|
||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
||||||
import { ObjectFilterDropdownCurrencySelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect';
|
import { ObjectFilterDropdownOperandDropdown } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandDropdown';
|
||||||
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
||||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||||
|
import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filter-dropdown/constants/DatePickerDropdownContentWidth';
|
||||||
import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
||||||
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
type ObjectFilterDropdownFilterInputProps = {
|
type ObjectFilterDropdownFilterInputProps = {
|
||||||
@ -36,11 +35,6 @@ export const ObjectFilterDropdownFilterInput = ({
|
|||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const subFieldNameUsedInDropdown = useRecoilComponentValueV2(
|
|
||||||
subFieldNameUsedInDropdownComponentState,
|
|
||||||
filterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||||
selectedOperandInDropdownComponentState,
|
selectedOperandInDropdownComponentState,
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
@ -69,74 +63,52 @@ export const ObjectFilterDropdownFilterInput = ({
|
|||||||
fieldMetadataItemUsedInDropdown.type,
|
fieldMetadataItemUsedInDropdown.type,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isNotASubFieldFilter = !isDefined(subFieldNameUsedInDropdown);
|
const isDateFilter = DATE_FILTER_TYPES.includes(filterType);
|
||||||
|
const isOnlyOperand = !isConfigurable;
|
||||||
|
|
||||||
return (
|
if (isOnlyOperand) {
|
||||||
<>
|
return (
|
||||||
{isConfigurable && selectedOperandInDropdown && (
|
<DropdownContent>
|
||||||
<>
|
<ObjectFilterDropdownOperandDropdown />
|
||||||
{TEXT_FILTER_TYPES.includes(filterType) && (
|
</DropdownContent>
|
||||||
<ObjectFilterDropdownTextInput />
|
);
|
||||||
)}
|
} else if (isDateFilter) {
|
||||||
{NUMBER_FILTER_TYPES.includes(filterType) && (
|
return (
|
||||||
<ObjectFilterDropdownNumberInput />
|
<DropdownContent widthInPixels={DATE_PICKER_DROPDOWN_CONTENT_WIDTH}>
|
||||||
)}
|
<ObjectFilterDropdownOperandDropdown />
|
||||||
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
<ObjectFilterDropdownDateInput />
|
||||||
{DATE_FILTER_TYPES.includes(filterType) && (
|
</DropdownContent>
|
||||||
<ObjectFilterDropdownDateInput />
|
);
|
||||||
)}
|
} else {
|
||||||
{filterType === 'RELATION' && (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<ObjectFilterDropdownSearchInput />
|
<ObjectFilterDropdownOperandDropdown />
|
||||||
<DropdownMenuSeparator />
|
{TEXT_FILTER_TYPES.includes(filterType) && (
|
||||||
<ObjectFilterDropdownRecordSelect
|
<ObjectFilterDropdownTextInput />
|
||||||
recordFilterId={recordFilterId}
|
)}
|
||||||
/>
|
{NUMBER_FILTER_TYPES.includes(filterType) && (
|
||||||
</>
|
<ObjectFilterDropdownNumberInput />
|
||||||
)}
|
)}
|
||||||
{filterType === 'ACTOR' && (
|
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
||||||
<>
|
{filterType === 'RELATION' && (
|
||||||
<ObjectFilterDropdownTextInput />
|
<>
|
||||||
</>
|
<ObjectFilterDropdownSearchInput />
|
||||||
)}
|
<DropdownMenuSeparator />
|
||||||
{filterType === 'ADDRESS' &&
|
<ObjectFilterDropdownRecordSelect recordFilterId={recordFilterId} />
|
||||||
(isNotASubFieldFilter ? (
|
</>
|
||||||
<>
|
)}
|
||||||
<ObjectFilterDropdownTextInput />
|
{filterType === 'ACTOR' && <ObjectFilterDropdownTextInput />}
|
||||||
</>
|
{filterType === 'ADDRESS' && <ObjectFilterDropdownTextInput />}
|
||||||
) : (
|
{filterType === 'CURRENCY' && <ObjectFilterDropdownNumberInput />}
|
||||||
<></>
|
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
||||||
))}
|
<>
|
||||||
{filterType === 'CURRENCY' &&
|
<ObjectFilterDropdownSearchInput />
|
||||||
(isExpectedSubFieldName(
|
<DropdownMenuSeparator />
|
||||||
FieldMetadataType.CURRENCY,
|
<ObjectFilterDropdownOptionSelect />
|
||||||
'currencyCode',
|
</>
|
||||||
subFieldNameUsedInDropdown,
|
)}
|
||||||
) ? (
|
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||||
<>
|
</DropdownContent>
|
||||||
<ObjectFilterDropdownCurrencySelect />
|
);
|
||||||
</>
|
}
|
||||||
) : isExpectedSubFieldName(
|
|
||||||
FieldMetadataType.CURRENCY,
|
|
||||||
'amountMicros',
|
|
||||||
subFieldNameUsedInDropdown,
|
|
||||||
) ? (
|
|
||||||
<>
|
|
||||||
<ObjectFilterDropdownNumberInput />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<ObjectFilterDropdownNumberInput />
|
|
||||||
))}
|
|
||||||
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
|
||||||
<>
|
|
||||||
<ObjectFilterDropdownSearchInput />
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<ObjectFilterDropdownOptionSelect />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,16 +5,20 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object-
|
|||||||
|
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { getOperandLabel } from '../utils/getOperandLabel';
|
|
||||||
import { IconChevronDown } from 'twenty-ui/display';
|
import { IconChevronDown } from 'twenty-ui/display';
|
||||||
|
import { getOperandLabel } from '../utils/getOperandLabel';
|
||||||
|
|
||||||
const StyledDropdownMenuHeader = styled(DropdownMenuHeader)`
|
const StyledDropdownMenuHeader = styled(DropdownMenuHeader)`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const OPERAND_DROPDOWN_CLICK_OUTSIDE_ID =
|
||||||
|
'object-filter-dropdown-operand-dropdown-click-outside-id';
|
||||||
|
|
||||||
export const ObjectFilterDropdownOperandDropdown = ({
|
export const ObjectFilterDropdownOperandDropdown = ({
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
}: {
|
}: {
|
||||||
@ -29,21 +33,25 @@ export const ObjectFilterDropdownOperandDropdown = ({
|
|||||||
const dropdownId = `${filterDropdownId}-operand-dropdown`;
|
const dropdownId = `${filterDropdownId}-operand-dropdown`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<ClickOutsideListenerContext.Provider
|
||||||
dropdownId={dropdownId}
|
value={{ excludedClickOutsideId: OPERAND_DROPDOWN_CLICK_OUTSIDE_ID }}
|
||||||
clickableComponent={
|
>
|
||||||
<StyledDropdownMenuHeader
|
<Dropdown
|
||||||
key={'selected-filter-operand'}
|
dropdownId={dropdownId}
|
||||||
EndComponent={<IconChevronDown />}
|
clickableComponent={
|
||||||
>
|
<StyledDropdownMenuHeader
|
||||||
{getOperandLabel(selectedOperandInDropdown)}
|
key={'selected-filter-operand'}
|
||||||
</StyledDropdownMenuHeader>
|
EndComponent={<IconChevronDown />}
|
||||||
}
|
>
|
||||||
dropdownComponents={<ObjectFilterDropdownOperandSelect />}
|
{getOperandLabel(selectedOperandInDropdown)}
|
||||||
dropdownHotkeyScope={{
|
</StyledDropdownMenuHeader>
|
||||||
scope: FiltersHotkeyScope.ObjectFilterDropdownOperandDropdown,
|
}
|
||||||
}}
|
dropdownComponents={<ObjectFilterDropdownOperandSelect />}
|
||||||
dropdownOffset={{ x: parseInt(theme.spacing(2), 10) }}
|
dropdownHotkeyScope={{
|
||||||
/>
|
scope: FiltersHotkeyScope.ObjectFilterDropdownOperandDropdown,
|
||||||
|
}}
|
||||||
|
dropdownOffset={{ x: parseInt(theme.spacing(2), 10) }}
|
||||||
|
/>
|
||||||
|
</ClickOutsideListenerContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useApplyObjectFilterDropdownOperand } from '@/object-record/object-filt
|
|||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -45,17 +46,19 @@ export const ObjectFilterDropdownOperandSelect = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
{operandsForFilterType.map((filterOperand, index) => (
|
<StyledDropdownMenuItemsContainer>
|
||||||
<MenuItem
|
{operandsForFilterType.map((filterOperand, index) => (
|
||||||
key={`select-filter-operand-${index}`}
|
<MenuItem
|
||||||
onClick={() => {
|
key={`select-filter-operand-${index}`}
|
||||||
handleOperandChange(filterOperand);
|
onClick={() => {
|
||||||
closeDropdown();
|
handleOperandChange(filterOperand);
|
||||||
}}
|
closeDropdown();
|
||||||
text={getOperandLabel(filterOperand)}
|
}}
|
||||||
/>
|
text={getOperandLabel(filterOperand)}
|
||||||
))}
|
/>
|
||||||
</StyledDropdownMenuItemsContainer>
|
))}
|
||||||
|
</StyledDropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
|
|
||||||
import { ObjectFilterDropdownOperandDropdown } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandDropdown';
|
|
||||||
|
|
||||||
type ObjectFilterOperandSelectAndInputProps = {
|
|
||||||
filterDropdownId?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ObjectFilterOperandSelectAndInput = ({
|
|
||||||
filterDropdownId,
|
|
||||||
}: ObjectFilterOperandSelectAndInputProps) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ObjectFilterDropdownOperandDropdown
|
|
||||||
filterDropdownId={filterDropdownId}
|
|
||||||
/>
|
|
||||||
<ObjectFilterDropdownFilterInput filterDropdownId={filterDropdownId} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const DATE_PICKER_DROPDOWN_CONTENT_WIDTH = 280;
|
||||||
@ -1,13 +1,14 @@
|
|||||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||||
import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable';
|
import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable';
|
||||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { IconChevronLeft, IconEyeOff } from 'twenty-ui/display';
|
import { IconChevronLeft, IconEyeOff } from 'twenty-ui/display';
|
||||||
import { MenuItemNavigate } from 'twenty-ui/navigation';
|
import { MenuItemNavigate } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ export const ObjectOptionsDropdownFieldsContent = () => {
|
|||||||
: handleColumnVisibilityChange;
|
: handleColumnVisibilityChange;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -79,6 +80,6 @@ export const ObjectOptionsDropdownFieldsContent = () => {
|
|||||||
text={t`Hidden Fields`}
|
text={t`Hidden Fields`}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,17 +7,18 @@ import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdow
|
|||||||
import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable';
|
import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable';
|
||||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { IconChevronLeft, IconSettings } from 'twenty-ui/display';
|
import { IconChevronLeft, IconSettings } from 'twenty-ui/display';
|
||||||
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
||||||
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
export const ObjectOptionsDropdownHiddenFieldsContent = () => {
|
export const ObjectOptionsDropdownHiddenFieldsContent = () => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
@ -61,7 +62,7 @@ export const ObjectOptionsDropdownHiddenFieldsContent = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -94,6 +95,6 @@ export const ObjectOptionsDropdownHiddenFieldsContent = () => {
|
|||||||
<MenuItem LeftIcon={IconSettings} text={t`Edit Fields`} />
|
<MenuItem LeftIcon={IconSettings} text={t`Edit Fields`} />
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,7 +8,9 @@ import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/use
|
|||||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
@ -16,10 +18,9 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { IconChevronLeft, IconSettings } from 'twenty-ui/display';
|
import { IconChevronLeft, IconSettings } from 'twenty-ui/display';
|
||||||
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
||||||
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
@ -68,20 +69,17 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
|||||||
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuHeader
|
||||||
<DropdownMenuHeader
|
StartComponent={
|
||||||
StartComponent={
|
<DropdownMenuHeaderLeftComponent
|
||||||
<DropdownMenuHeaderLeftComponent
|
onClick={() => onContentChange('recordGroups')}
|
||||||
onClick={() => onContentChange('recordGroups')}
|
Icon={IconChevronLeft}
|
||||||
Icon={IconChevronLeft}
|
/>
|
||||||
/>
|
}
|
||||||
}
|
>
|
||||||
>
|
Hidden {recordGroupFieldMetadata?.label}
|
||||||
Hidden {recordGroupFieldMetadata?.label}
|
</DropdownMenuHeader>
|
||||||
</DropdownMenuHeader>
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
|
|
||||||
<RecordGroupsVisibilityDropdownSection
|
<RecordGroupsVisibilityDropdownSection
|
||||||
title={`Hidden ${recordGroupFieldMetadata?.label}`}
|
title={`Hidden ${recordGroupFieldMetadata?.label}`}
|
||||||
recordGroupIds={hiddenRecordGroupIds}
|
recordGroupIds={hiddenRecordGroupIds}
|
||||||
@ -102,6 +100,6 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
|||||||
<MenuItem LeftIcon={IconSettings} text={t`Edit field values`} />
|
<MenuItem LeftIcon={IconSettings} text={t`Edit field values`} />
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { useSetViewTypeFromLayoutOptionsMenu } from '@/object-record/object-opti
|
|||||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -92,7 +93,7 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -234,6 +235,6 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
|||||||
</SelectableList>
|
</SelectableList>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
)}
|
)}
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hook
|
|||||||
import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions';
|
import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions';
|
||||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -38,7 +39,7 @@ export const ObjectOptionsDropdownLayoutOpenInContent = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -105,6 +106,6 @@ export const ObjectOptionsDropdownLayoutOpenInContent = () => {
|
|||||||
</SelectableListItem>
|
</SelectableListItem>
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { recordGroupFieldMetadataComponentState } from '@/object-record/record-g
|
|||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
@ -93,7 +94,7 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
{currentView && (
|
{currentView && (
|
||||||
<ObjectOptionsDropdownMenuViewName currentView={currentView} />
|
<ObjectOptionsDropdownMenuViewName currentView={currentView} />
|
||||||
)}
|
)}
|
||||||
@ -121,7 +122,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
</SelectableListItem>
|
</SelectableListItem>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
|
|
||||||
<DropdownMenuItemsContainer scrollable={false}>
|
<DropdownMenuItemsContainer scrollable={false}>
|
||||||
<SelectableListItem
|
<SelectableListItem
|
||||||
itemId="Fields"
|
itemId="Fields"
|
||||||
@ -136,7 +136,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
hasSubMenu
|
hasSubMenu
|
||||||
/>
|
/>
|
||||||
</SelectableListItem>
|
</SelectableListItem>
|
||||||
|
|
||||||
<div id="group-by-menu-item">
|
<div id="group-by-menu-item">
|
||||||
<SelectableListItem
|
<SelectableListItem
|
||||||
itemId="Group"
|
itemId="Group"
|
||||||
@ -175,7 +174,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
|
|
||||||
<SelectableListItem
|
<SelectableListItem
|
||||||
itemId="Copy link to view"
|
itemId="Copy link to view"
|
||||||
onEnter={() => {
|
onEnter={() => {
|
||||||
@ -228,6 +226,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { recordGroupFieldMetadataComponentState } from '@/object-record/record-g
|
|||||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||||
import { useHandleRecordGroupField } from '@/object-record/record-index/hooks/useHandleRecordGroupField';
|
import { useHandleRecordGroupField } from '@/object-record/record-index/hooks/useHandleRecordGroupField';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -103,7 +104,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
|||||||
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -124,6 +125,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
|||||||
placeholder={t`Search fields`}
|
placeholder={t`Search fields`}
|
||||||
onChange={(event) => setRecordGroupFieldSearchInput(event.target.value)}
|
onChange={(event) => setRecordGroupFieldSearchInput(event.target.value)}
|
||||||
/>
|
/>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{viewType === ViewType.Table && (
|
{viewType === ViewType.Table && (
|
||||||
<MenuItemSelect
|
<MenuItemSelect
|
||||||
@ -154,6 +156,6 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
|||||||
<MenuItem LeftIcon={IconSettings} text={t`Create select field`} />
|
<MenuItem LeftIcon={IconSettings} text={t`Create select field`} />
|
||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-gr
|
|||||||
import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort';
|
import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort';
|
||||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -58,7 +59,7 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -123,6 +124,6 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
|||||||
</SelectableListItem>
|
</SelectableListItem>
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/re
|
|||||||
import { recordIndexRecordGroupHideComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentFamilyState';
|
import { recordIndexRecordGroupHideComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentFamilyState';
|
||||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -94,7 +95,7 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -192,6 +193,6 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
|||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,19 +10,19 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-fi
|
|||||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||||
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
|
||||||
|
|
||||||
const instanceId = 'entity-options-scope';
|
const instanceId = 'entity-options-scope';
|
||||||
|
|
||||||
@ -111,9 +111,9 @@ const createStory = (contentId: ObjectOptionsContentId | null): Story => ({
|
|||||||
dropdownId: OBJECT_OPTIONS_DROPDOWN_ID,
|
dropdownId: OBJECT_OPTIONS_DROPDOWN_ID,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DropdownMenu>
|
<DropdownContent>
|
||||||
<Story />
|
<Story />
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</ObjectOptionsDropdownContext.Provider>
|
</ObjectOptionsDropdownContext.Provider>
|
||||||
</RecordIndexContextProvider>
|
</RecordIndexContextProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import {
|
|||||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
@ -232,88 +233,91 @@ export const ObjectSortDropdownButton = ({
|
|||||||
</StyledHeaderDropdownButton>
|
</StyledHeaderDropdownButton>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<SelectableList
|
<DropdownContent>
|
||||||
selectableListInstanceId={OBJECT_SORT_DROPDOWN_ID}
|
<SelectableList
|
||||||
hotkeyScope={hotkeyScope.scope}
|
selectableListInstanceId={OBJECT_SORT_DROPDOWN_ID}
|
||||||
selectableItemIdArray={selectableItemIdArray}
|
hotkeyScope={hotkeyScope.scope}
|
||||||
>
|
selectableItemIdArray={selectableItemIdArray}
|
||||||
{isRecordSortDirectionMenuUnfolded && (
|
|
||||||
<StyledSelectedSortDirectionContainer>
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
{RECORD_SORT_DIRECTIONS.map((sortDirection, index) => (
|
|
||||||
<MenuItem
|
|
||||||
key={index}
|
|
||||||
focused={selectedItemId === sortDirection}
|
|
||||||
onClick={() => handleSortDirectionClick(sortDirection)}
|
|
||||||
text={
|
|
||||||
sortDirection === 'asc' ? t`Ascending` : t`Descending`
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
</StyledSelectedSortDirectionContainer>
|
|
||||||
)}
|
|
||||||
<DropdownMenuHeader
|
|
||||||
onClick={() =>
|
|
||||||
setIsRecordSortDirectionMenuUnfolded(
|
|
||||||
!isRecordSortDirectionMenuUnfolded,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
EndComponent={
|
|
||||||
<StyledDropdownMenuHeaderEndComponent>
|
|
||||||
<IconChevronDown size={theme.icon.size.md} />
|
|
||||||
</StyledDropdownMenuHeaderEndComponent>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{selectedRecordSortDirection === 'asc'
|
{isRecordSortDirectionMenuUnfolded && (
|
||||||
? t`Ascending`
|
<StyledSelectedSortDirectionContainer>
|
||||||
: t`Descending`}
|
<DropdownMenuItemsContainer>
|
||||||
</DropdownMenuHeader>
|
{RECORD_SORT_DIRECTIONS.map((sortDirection, index) => (
|
||||||
<DropdownMenuSeparator />
|
<MenuItem
|
||||||
<StyledInput
|
key={index}
|
||||||
autoFocus
|
focused={selectedItemId === sortDirection}
|
||||||
value={objectSortDropdownSearchInput}
|
onClick={() => handleSortDirectionClick(sortDirection)}
|
||||||
placeholder={t`Search fields`}
|
text={
|
||||||
onChange={(event) =>
|
sortDirection === 'asc' ? t`Ascending` : t`Descending`
|
||||||
setObjectSortDropdownSearchInput(event.target.value)
|
}
|
||||||
}
|
/>
|
||||||
/>
|
))}
|
||||||
<DropdownMenuItemsContainer scrollable={false}>
|
</DropdownMenuItemsContainer>
|
||||||
{visibleFieldMetadataItems.map(
|
</StyledSelectedSortDirectionContainer>
|
||||||
(visibleFieldMetadataItem, index) => (
|
|
||||||
<SelectableListItem
|
|
||||||
key={visibleFieldMetadataItem.id}
|
|
||||||
itemId={visibleFieldMetadataItem.id}
|
|
||||||
onEnter={() => handleAddSort(visibleFieldMetadataItem)}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
focused={selectedItemId === visibleFieldMetadataItem.id}
|
|
||||||
testId={`visible-select-sort-${index}`}
|
|
||||||
onClick={() => handleAddSort(visibleFieldMetadataItem)}
|
|
||||||
LeftIcon={getIcon(visibleFieldMetadataItem.icon)}
|
|
||||||
text={visibleFieldMetadataItem.label}
|
|
||||||
/>
|
|
||||||
</SelectableListItem>
|
|
||||||
),
|
|
||||||
)}
|
)}
|
||||||
{shouldShowSeparator && <DropdownMenuSeparator />}
|
<DropdownMenuHeader
|
||||||
{hiddenFieldMetadataItems.map((hiddenFieldMetadataItem, index) => (
|
onClick={() =>
|
||||||
<SelectableListItem
|
setIsRecordSortDirectionMenuUnfolded(
|
||||||
key={hiddenFieldMetadataItem.id}
|
!isRecordSortDirectionMenuUnfolded,
|
||||||
itemId={hiddenFieldMetadataItem.id}
|
)
|
||||||
onEnter={() => handleAddSort(hiddenFieldMetadataItem)}
|
}
|
||||||
>
|
EndComponent={
|
||||||
<MenuItem
|
<StyledDropdownMenuHeaderEndComponent>
|
||||||
focused={selectedItemId === hiddenFieldMetadataItem.id}
|
<IconChevronDown size={theme.icon.size.md} />
|
||||||
testId={`hidden-select-sort-${index}`}
|
</StyledDropdownMenuHeaderEndComponent>
|
||||||
onClick={() => handleAddSort(hiddenFieldMetadataItem)}
|
}
|
||||||
LeftIcon={getIcon(hiddenFieldMetadataItem.icon)}
|
>
|
||||||
text={hiddenFieldMetadataItem.label}
|
{selectedRecordSortDirection === 'asc'
|
||||||
/>
|
? t`Ascending`
|
||||||
</SelectableListItem>
|
: t`Descending`}
|
||||||
))}
|
</DropdownMenuHeader>
|
||||||
</DropdownMenuItemsContainer>
|
<StyledInput
|
||||||
</SelectableList>
|
autoFocus
|
||||||
|
value={objectSortDropdownSearchInput}
|
||||||
|
placeholder={t`Search fields`}
|
||||||
|
onChange={(event) =>
|
||||||
|
setObjectSortDropdownSearchInput(event.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<DropdownMenuItemsContainer scrollable={false}>
|
||||||
|
{visibleFieldMetadataItems.map(
|
||||||
|
(visibleFieldMetadataItem, index) => (
|
||||||
|
<SelectableListItem
|
||||||
|
key={visibleFieldMetadataItem.id}
|
||||||
|
itemId={visibleFieldMetadataItem.id}
|
||||||
|
onEnter={() => handleAddSort(visibleFieldMetadataItem)}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
focused={selectedItemId === visibleFieldMetadataItem.id}
|
||||||
|
testId={`visible-select-sort-${index}`}
|
||||||
|
onClick={() => handleAddSort(visibleFieldMetadataItem)}
|
||||||
|
LeftIcon={getIcon(visibleFieldMetadataItem.icon)}
|
||||||
|
text={visibleFieldMetadataItem.label}
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
{shouldShowSeparator && <DropdownMenuSeparator />}
|
||||||
|
{hiddenFieldMetadataItems.map(
|
||||||
|
(hiddenFieldMetadataItem, index) => (
|
||||||
|
<SelectableListItem
|
||||||
|
key={hiddenFieldMetadataItem.id}
|
||||||
|
itemId={hiddenFieldMetadataItem.id}
|
||||||
|
onEnter={() => handleAddSort(hiddenFieldMetadataItem)}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
focused={selectedItemId === hiddenFieldMetadataItem.id}
|
||||||
|
testId={`hidden-select-sort-${index}`}
|
||||||
|
onClick={() => handleAddSort(hiddenFieldMetadataItem)}
|
||||||
|
LeftIcon={getIcon(hiddenFieldMetadataItem.icon)}
|
||||||
|
text={hiddenFieldMetadataItem.label}
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</SelectableList>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
onClose={handleDropdownButtonClose}
|
onClose={handleDropdownButtonClose}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import styled from '@emotion/styled';
|
|||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
|
|
||||||
import { useRecordGroupActions } from '@/object-record/record-group/hooks/useRecordGroupActions';
|
import { useRecordGroupActions } from '@/object-record/record-group/hooks/useRecordGroupActions';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
@ -22,7 +22,6 @@ type RecordBoardColumnDropdownMenuProps = {
|
|||||||
stageId: string;
|
stageId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: unify and use Dropdown component
|
|
||||||
export const RecordBoardColumnDropdownMenu = ({
|
export const RecordBoardColumnDropdownMenu = ({
|
||||||
onClose,
|
onClose,
|
||||||
}: RecordBoardColumnDropdownMenuProps) => {
|
}: RecordBoardColumnDropdownMenuProps) => {
|
||||||
@ -45,7 +44,7 @@ export const RecordBoardColumnDropdownMenu = ({
|
|||||||
return (
|
return (
|
||||||
<StyledMenuContainer ref={boardColumnMenuRef}>
|
<StyledMenuContainer ref={boardColumnMenuRef}>
|
||||||
<OverlayContainer>
|
<OverlayContainer>
|
||||||
<DropdownMenu data-select-disable>
|
<DropdownContent selectDisabled>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{recordGroupActions.map((action) => (
|
{recordGroupActions.map((action) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@ -59,7 +58,7 @@ export const RecordBoardColumnDropdownMenu = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</OverlayContainer>
|
</OverlayContainer>
|
||||||
</StyledMenuContainer>
|
</StyledMenuContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { DROPDOWN_OFFSET_Y } from '@/dropdown/constants/DropdownOffsetY';
|
import { DROPDOWN_OFFSET_Y } from '@/dropdown/constants/DropdownOffsetY';
|
||||||
import { DROPDOWN_WIDTH } from '@/dropdown/constants/DropdownWidth';
|
|
||||||
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext } from '@/object-record/record-board/contexts/RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext';
|
import { RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext } from '@/object-record/record-board/contexts/RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext';
|
||||||
@ -46,7 +45,6 @@ export const RecordBoardColumnHeaderAggregateDropdown = ({
|
|||||||
dropdownHotkeyScope={{
|
dropdownHotkeyScope={{
|
||||||
scope: RecordBoardColumnHotkeyScope.ColumnHeader,
|
scope: RecordBoardColumnHotkeyScope.ColumnHeader,
|
||||||
}}
|
}}
|
||||||
dropdownWidth={DROPDOWN_WIDTH}
|
|
||||||
dropdownOffset={{ y: DROPDOWN_OFFSET_Y }}
|
dropdownOffset={{ y: DROPDOWN_OFFSET_Y }}
|
||||||
clickableComponent={
|
clickableComponent={
|
||||||
<RecordBoardColumnHeaderAggregateDropdownButton
|
<RecordBoardColumnHeaderAggregateDropdownButton
|
||||||
|
|||||||
@ -4,12 +4,13 @@ import { aggregateOperationComponentState } from '@/object-record/record-board/r
|
|||||||
import { availableFieldIdsForAggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState';
|
import { availableFieldIdsForAggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState';
|
||||||
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 { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate';
|
import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import {
|
import {
|
||||||
Icon123,
|
Icon123,
|
||||||
@ -48,7 +49,7 @@ export const RecordBoardColumnHeaderAggregateDropdownFieldsContent = () => {
|
|||||||
|
|
||||||
if (!isDefined(aggregateOperation)) return <></>;
|
if (!isDefined(aggregateOperation)) return <></>;
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -94,6 +95,6 @@ export const RecordBoardColumnHeaderAggregateDropdownFieldsContent = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
} from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
|
} from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
|
||||||
|
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
@ -29,7 +30,7 @@ export const RecordBoardColumnHeaderAggregateDropdownMenuContent = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -60,6 +61,6 @@ export const RecordBoardColumnHeaderAggregateDropdownMenuContent = () => {
|
|||||||
hasSubMenu
|
hasSubMenu
|
||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,9 @@ import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/Agg
|
|||||||
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
import { AvailableFieldsForAggregateOperation } from '@/object-record/types/AvailableFieldsForAggregateOperation';
|
import { AvailableFieldsForAggregateOperation } from '@/object-record/types/AvailableFieldsForAggregateOperation';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
@ -20,7 +22,6 @@ import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate';
|
|||||||
import isEmpty from 'lodash.isempty';
|
import isEmpty from 'lodash.isempty';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { IconCheck, IconChevronLeft } from 'twenty-ui/display';
|
import { IconCheck, IconChevronLeft } from 'twenty-ui/display';
|
||||||
|
|
||||||
export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
|
export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
|
||||||
@ -58,7 +59,7 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -121,6 +122,6 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
|
|||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
} from '@/object-record/record-field/meta-types/input/components/MultiItemBaseInput';
|
} from '@/object-record/record-field/meta-types/input/components/MultiItemBaseInput';
|
||||||
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputClickOutsideEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { PhoneRecord } from '@/object-record/record-field/types/FieldMetadata';
|
import { PhoneRecord } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
@ -181,7 +181,7 @@ export const MultiItemFieldInput = <T,>({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu ref={containerRef} width={200}>
|
<DropdownContent ref={containerRef}>
|
||||||
{!!items.length && (
|
{!!items.length && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
@ -232,6 +232,6 @@ export const MultiItemFieldInput = <T,>({
|
|||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
)}
|
)}
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { MenuItemWithOptionDropdown } from '@/ui/navigation/menu-item/components/MenuItemWithOptionDropdown';
|
import { MenuItemWithOptionDropdown } from '@/ui/navigation/menu-item/components/MenuItemWithOptionDropdown';
|
||||||
@ -73,26 +74,28 @@ export const MultiItemFieldMenuItem = <T,>({
|
|||||||
RightIcon={!isHovered && showPrimaryIcon ? IconBookmark : null}
|
RightIcon={!isHovered && showPrimaryIcon ? IconBookmark : null}
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
dropdownContent={
|
dropdownContent={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
{showSetAsPrimaryButton && (
|
<DropdownMenuItemsContainer>
|
||||||
|
{showSetAsPrimaryButton && (
|
||||||
|
<MenuItem
|
||||||
|
LeftIcon={IconBookmarkPlus}
|
||||||
|
text="Set as Primary"
|
||||||
|
onClick={handleSetAsPrimaryClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
LeftIcon={IconBookmarkPlus}
|
LeftIcon={IconPencil}
|
||||||
text="Set as Primary"
|
text="Edit"
|
||||||
onClick={handleSetAsPrimaryClick}
|
onClick={handleEditClick}
|
||||||
/>
|
/>
|
||||||
)}
|
<MenuItem
|
||||||
<MenuItem
|
accent="danger"
|
||||||
LeftIcon={IconPencil}
|
LeftIcon={IconTrash}
|
||||||
text="Edit"
|
text="Delete"
|
||||||
onClick={handleEditClick}
|
onClick={handleDeleteClick}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
</DropdownMenuItemsContainer>
|
||||||
accent="danger"
|
</DropdownContent>
|
||||||
LeftIcon={IconTrash}
|
|
||||||
text="Delete"
|
|
||||||
onClick={handleDeleteClick}
|
|
||||||
/>
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,99 +0,0 @@
|
|||||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
|
||||||
import { availableRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/availableRecordGroupIdsComponentSelector';
|
|
||||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
|
||||||
import { RecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem';
|
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
|
||||||
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
|
|
||||||
import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|
||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
|
|
||||||
type RecordIndexAddRecordInGroupDropdownProps = {
|
|
||||||
dropdownId: string;
|
|
||||||
clickableComponent: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const RecordIndexAddRecordInGroupDropdown = ({
|
|
||||||
dropdownId,
|
|
||||||
clickableComponent,
|
|
||||||
}: RecordIndexAddRecordInGroupDropdownProps) => {
|
|
||||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
|
||||||
|
|
||||||
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
|
||||||
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
|
||||||
|
|
||||||
const recordGroupIds = useRecoilComponentValueV2(
|
|
||||||
availableRecordGroupIdsComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
|
||||||
recordGroupFieldMetadataComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isRecordGroupTableSectionToggledState =
|
|
||||||
useRecoilComponentCallbackStateV2(
|
|
||||||
isRecordGroupTableSectionToggledComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectFieldMetadataItem = objectMetadataItem.fields.find(
|
|
||||||
(field) => field.id === recordGroupFieldMetadata?.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(dropdownId);
|
|
||||||
|
|
||||||
const { createNewIndexRecord } = useCreateNewIndexRecord({
|
|
||||||
objectMetadataItem,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleCreateNewTableRecordInGroup = useRecoilCallback(
|
|
||||||
({ set }) =>
|
|
||||||
(recordGroup: RecordGroupDefinition) => {
|
|
||||||
set(isRecordGroupTableSectionToggledState(recordGroup.id), true);
|
|
||||||
setActiveDropdownFocusIdAndMemorizePrevious(null);
|
|
||||||
if (!selectFieldMetadataItem) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
createNewIndexRecord({
|
|
||||||
[selectFieldMetadataItem.name]: recordGroup.value,
|
|
||||||
});
|
|
||||||
closeDropdown();
|
|
||||||
},
|
|
||||||
[
|
|
||||||
isRecordGroupTableSectionToggledState,
|
|
||||||
setActiveDropdownFocusIdAndMemorizePrevious,
|
|
||||||
selectFieldMetadataItem,
|
|
||||||
createNewIndexRecord,
|
|
||||||
closeDropdown,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!selectFieldMetadataItem) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
dropdownWidth="200px"
|
|
||||||
dropdownPlacement="bottom-start"
|
|
||||||
clickableComponent={clickableComponent}
|
|
||||||
dropdownId={dropdownId}
|
|
||||||
dropdownComponents={
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
{recordGroupIds.map((recordGroupId) => (
|
|
||||||
<RecordIndexPageKanbanAddMenuItem
|
|
||||||
key={recordGroupId}
|
|
||||||
columnId={recordGroupId}
|
|
||||||
onItemClick={handleCreateNewTableRecordInGroup}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
}
|
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -9,7 +9,7 @@ import { RecordPickerLayoutDirection } from '@/object-record/record-picker/types
|
|||||||
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
||||||
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
||||||
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
|
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
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 { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
@ -110,7 +110,7 @@ export const MultipleRecordPicker = ({
|
|||||||
containerRef={containerRef}
|
containerRef={containerRef}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
/>
|
/>
|
||||||
<DropdownMenu ref={containerRef} data-select-disable width={200}>
|
<DropdownContent ref={containerRef}>
|
||||||
{layoutDirection === 'search-bar-on-bottom' && (
|
{layoutDirection === 'search-bar-on-bottom' && (
|
||||||
<>
|
<>
|
||||||
{createNewButtonSection}
|
{createNewButtonSection}
|
||||||
@ -124,7 +124,7 @@ export const MultipleRecordPicker = ({
|
|||||||
{createNewButtonSection}
|
{createNewButtonSection}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</MultipleRecordPickerComponentInstanceContext.Provider>
|
</MultipleRecordPickerComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
SingleRecordPickerMenuItemsWithSearchProps,
|
SingleRecordPickerMenuItemsWithSearchProps,
|
||||||
} from '@/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch';
|
} from '@/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch';
|
||||||
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
|
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ export const SingleRecordPicker = ({
|
|||||||
<SingleRecordPickerComponentInstanceContext.Provider
|
<SingleRecordPickerComponentInstanceContext.Provider
|
||||||
value={{ instanceId: componentInstanceId }}
|
value={{ instanceId: componentInstanceId }}
|
||||||
>
|
>
|
||||||
<DropdownMenu ref={containerRef} data-select-disable>
|
<DropdownContent ref={containerRef}>
|
||||||
<SingleRecordPickerMenuItemsWithSearch
|
<SingleRecordPickerMenuItemsWithSearch
|
||||||
{...{
|
{...{
|
||||||
EmptyIcon,
|
EmptyIcon,
|
||||||
@ -62,7 +62,7 @@ export const SingleRecordPicker = ({
|
|||||||
layoutDirection,
|
layoutDirection,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</SingleRecordPickerComponentInstanceContext.Provider>
|
</SingleRecordPickerComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import { getForeignKeyNameFromRelationFieldName } from '@/object-record/utils/ge
|
|||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||||
@ -246,21 +247,23 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
LeftIcon={IconUnlink}
|
|
||||||
text="Detach"
|
|
||||||
onClick={handleDetach}
|
|
||||||
/>
|
|
||||||
{!isAccountOwnerRelation && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
LeftIcon={IconTrash}
|
LeftIcon={IconUnlink}
|
||||||
text="Delete"
|
text="Detach"
|
||||||
accent="danger"
|
onClick={handleDetach}
|
||||||
onClick={handleDelete}
|
|
||||||
/>
|
/>
|
||||||
)}
|
{!isAccountOwnerRelation && (
|
||||||
</DropdownMenuItemsContainer>
|
<MenuItem
|
||||||
|
LeftIcon={IconTrash}
|
||||||
|
text="Delete"
|
||||||
|
accent="danger"
|
||||||
|
onClick={handleDelete}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownScopeId }}
|
dropdownHotkeyScope={{ scope: dropdownScopeId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -2,13 +2,14 @@ import { RecordTableColumnAggregateFooterAggregateOperationMenuItems } from '@/o
|
|||||||
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
|
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
|
||||||
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { IconChevronLeft } from 'twenty-ui/display';
|
import { IconChevronLeft } from 'twenty-ui/display';
|
||||||
|
|
||||||
export const RecordTableColumnAggregateFooterDropdownSubmenuContent = ({
|
export const RecordTableColumnAggregateFooterDropdownSubmenuContent = ({
|
||||||
@ -32,7 +33,7 @@ export const RecordTableColumnAggregateFooterDropdownSubmenuContent = ({
|
|||||||
TableOptionsHotkeyScope.Dropdown,
|
TableOptionsHotkeyScope.Dropdown,
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -48,6 +49,6 @@ export const RecordTableColumnAggregateFooterDropdownSubmenuContent = ({
|
|||||||
aggregateOperations={aggregateOperations}
|
aggregateOperations={aggregateOperations}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,16 +5,17 @@ import { NON_STANDARD_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record
|
|||||||
import { useViewFieldAggregateOperation } from '@/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation';
|
import { useViewFieldAggregateOperation } from '@/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation';
|
||||||
import { getAvailableAggregateOperationsForFieldMetadataType } from '@/object-record/record-table/record-table-footer/utils/getAvailableAggregateOperationsForFieldMetadataType';
|
import { getAvailableAggregateOperationsForFieldMetadataType } from '@/object-record/record-table/record-table-footer/utils/getAvailableAggregateOperationsForFieldMetadataType';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { useContext, useMemo } from 'react';
|
import { useContext, useMemo } from 'react';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
|
||||||
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
|
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
|
||||||
import { IconCheck } from 'twenty-ui/display';
|
import { IconCheck } from 'twenty-ui/display';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export const RecordTableColumnAggregateFooterMenuContent = () => {
|
export const RecordTableColumnAggregateFooterMenuContent = () => {
|
||||||
const {
|
const {
|
||||||
@ -64,7 +65,7 @@ export const RecordTableColumnAggregateFooterMenuContent = () => {
|
|||||||
} = useViewFieldAggregateOperation();
|
} = useViewFieldAggregateOperation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -116,6 +117,6 @@ export const RecordTableColumnAggregateFooterMenuContent = () => {
|
|||||||
aria-selected={!isDefined(currentViewFieldAggregateOperation)}
|
aria-selected={!isDefined(currentViewFieldAggregateOperation)}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|||||||
import { useOpenRecordFilterChipFromTableHeader } from '@/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader';
|
import { useOpenRecordFilterChipFromTableHeader } from '@/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader';
|
||||||
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState';
|
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper';
|
import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
@ -107,43 +108,45 @@ export const RecordTableColumnHeadDropdownMenu = ({
|
|||||||
const canHide = column.isLabelIdentifier !== true;
|
const canHide = column.isLabelIdentifier !== true;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
{isFilterable && (
|
<StyledDropdownMenuItemsContainer>
|
||||||
<MenuItem
|
{isFilterable && (
|
||||||
LeftIcon={IconFilter}
|
<MenuItem
|
||||||
onClick={handleFilterClick}
|
LeftIcon={IconFilter}
|
||||||
text={t`Filter`}
|
onClick={handleFilterClick}
|
||||||
/>
|
text={t`Filter`}
|
||||||
)}
|
/>
|
||||||
{isSortable && (
|
)}
|
||||||
<MenuItem
|
{isSortable && (
|
||||||
LeftIcon={IconSortDescending}
|
<MenuItem
|
||||||
onClick={handleSortClick}
|
LeftIcon={IconSortDescending}
|
||||||
text={t`Sort`}
|
onClick={handleSortClick}
|
||||||
/>
|
text={t`Sort`}
|
||||||
)}
|
/>
|
||||||
{showSeparator && <DropdownMenuSeparator />}
|
)}
|
||||||
{canMoveLeft && (
|
{showSeparator && <DropdownMenuSeparator />}
|
||||||
<MenuItem
|
{canMoveLeft && (
|
||||||
LeftIcon={IconArrowLeft}
|
<MenuItem
|
||||||
onClick={handleColumnMoveLeft}
|
LeftIcon={IconArrowLeft}
|
||||||
text={t`Move left`}
|
onClick={handleColumnMoveLeft}
|
||||||
/>
|
text={t`Move left`}
|
||||||
)}
|
/>
|
||||||
{canMoveRight && (
|
)}
|
||||||
<MenuItem
|
{canMoveRight && (
|
||||||
LeftIcon={IconArrowRight}
|
<MenuItem
|
||||||
onClick={handleColumnMoveRight}
|
LeftIcon={IconArrowRight}
|
||||||
text={t`Move right`}
|
onClick={handleColumnMoveRight}
|
||||||
/>
|
text={t`Move right`}
|
||||||
)}
|
/>
|
||||||
{canHide && (
|
)}
|
||||||
<MenuItem
|
{canHide && (
|
||||||
LeftIcon={IconEyeOff}
|
<MenuItem
|
||||||
onClick={handleColumnVisibility}
|
LeftIcon={IconEyeOff}
|
||||||
text={t`Hide`}
|
onClick={handleColumnVisibility}
|
||||||
/>
|
text={t`Hide`}
|
||||||
)}
|
/>
|
||||||
</StyledDropdownMenuItemsContainer>
|
)}
|
||||||
|
</StyledDropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,15 +8,16 @@ import { useTableColumns } from '@/object-record/record-table/hooks/useTableColu
|
|||||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { IconSettings, useIcons } from 'twenty-ui/display';
|
import { IconSettings, useIcons } from 'twenty-ui/display';
|
||||||
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
||||||
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
export const RecordTableHeaderPlusButtonContent = () => {
|
export const RecordTableHeaderPlusButtonContent = () => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
@ -45,7 +46,7 @@ export const RecordTableHeaderPlusButtonContent = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{hiddenTableColumns.map((column) => (
|
{hiddenTableColumns.map((column) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@ -70,6 +71,6 @@ export const RecordTableHeaderPlusButtonContent = () => {
|
|||||||
<MenuItem LeftIcon={IconSettings} text={t`Customize fields`} />
|
<MenuItem LeftIcon={IconSettings} text={t`Customize fields`} />
|
||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { Key } from 'ts-key-enum';
|
|||||||
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
||||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||||
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
@ -80,47 +81,49 @@ export const MultipleSelectDropdown = ({
|
|||||||
const selectableItemIds = itemsInDropdown.map((item) => item.id);
|
const selectableItemIds = itemsInDropdown.map((item) => item.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectableList
|
<DropdownContent>
|
||||||
selectableListInstanceId={selectableListId}
|
<SelectableList
|
||||||
selectableItemIdArray={selectableItemIds}
|
selectableListInstanceId={selectableListId}
|
||||||
hotkeyScope={hotkeyScope}
|
selectableItemIdArray={selectableItemIds}
|
||||||
>
|
hotkeyScope={hotkeyScope}
|
||||||
<DropdownMenuItemsContainer hasMaxHeight width="auto">
|
>
|
||||||
{itemsInDropdown?.map((item) => {
|
<DropdownMenuItemsContainer hasMaxHeight width="auto">
|
||||||
return (
|
{itemsInDropdown?.map((item) => {
|
||||||
<SelectableListItem
|
return (
|
||||||
itemId={item.id}
|
<SelectableListItem
|
||||||
onEnter={() => {
|
itemId={item.id}
|
||||||
resetSelectedItem();
|
onEnter={() => {
|
||||||
handleItemSelectChange(item, !item.isSelected);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItemMultiSelectAvatar
|
|
||||||
key={item.id}
|
|
||||||
selected={item.isSelected}
|
|
||||||
isKeySelected={item.id === selectedItemId}
|
|
||||||
onSelectChange={(newCheckedValue) => {
|
|
||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
handleItemSelectChange(item, newCheckedValue);
|
handleItemSelectChange(item, !item.isSelected);
|
||||||
}}
|
}}
|
||||||
avatar={
|
>
|
||||||
<StyledMultipleSelectDropdownAvatarChip
|
<MenuItemMultiSelectAvatar
|
||||||
className="avatar-icon-container"
|
key={item.id}
|
||||||
name={item.name}
|
selected={item.isSelected}
|
||||||
avatarUrl={item.avatarUrl}
|
isKeySelected={item.id === selectedItemId}
|
||||||
LeftIcon={item.AvatarIcon}
|
onSelectChange={(newCheckedValue) => {
|
||||||
avatarType={item.avatarType}
|
resetSelectedItem();
|
||||||
isIconInverted={item.isIconInverted}
|
handleItemSelectChange(item, newCheckedValue);
|
||||||
placeholderColorSeed={item.id}
|
}}
|
||||||
/>
|
avatar={
|
||||||
}
|
<StyledMultipleSelectDropdownAvatarChip
|
||||||
/>
|
className="avatar-icon-container"
|
||||||
</SelectableListItem>
|
name={item.name}
|
||||||
);
|
avatarUrl={item.avatarUrl}
|
||||||
})}
|
LeftIcon={item.AvatarIcon}
|
||||||
{showNoResult && <MenuItem text="No results" />}
|
avatarType={item.avatarType}
|
||||||
{loadingItems && <DropdownMenuSkeletonItem />}
|
isIconInverted={item.isIconInverted}
|
||||||
</DropdownMenuItemsContainer>
|
placeholderColorSeed={item.id}
|
||||||
</SelectableList>
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{showNoResult && <MenuItem text="No results" />}
|
||||||
|
{loadingItems && <DropdownMenuSkeletonItem />}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</SelectableList>
|
||||||
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useDestroyOneRecord } from '@/object-record/hooks/useDestroyOneRecord';
|
|||||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
@ -54,45 +55,46 @@ export const SettingsAccountsRowDropdownMenu = ({
|
|||||||
clickableComponent={
|
clickableComponent={
|
||||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
LeftIcon={IconMail}
|
|
||||||
text={t`Emails settings`}
|
|
||||||
onClick={() => {
|
|
||||||
navigate(SettingsPath.AccountsEmails);
|
|
||||||
closeDropdown();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
LeftIcon={IconCalendarEvent}
|
|
||||||
text={t`Calendar settings`}
|
|
||||||
onClick={() => {
|
|
||||||
navigate(SettingsPath.AccountsCalendars);
|
|
||||||
closeDropdown();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{account.authFailedAt && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
LeftIcon={IconRefresh}
|
LeftIcon={IconMail}
|
||||||
text={t`Reconnect`}
|
text={t`Emails settings`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
triggerApisOAuth(account.provider);
|
navigate(SettingsPath.AccountsEmails);
|
||||||
closeDropdown();
|
closeDropdown();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
<MenuItem
|
||||||
<MenuItem
|
LeftIcon={IconCalendarEvent}
|
||||||
accent="danger"
|
text={t`Calendar settings`}
|
||||||
LeftIcon={IconTrash}
|
onClick={() => {
|
||||||
text={t`Remove account`}
|
navigate(SettingsPath.AccountsCalendars);
|
||||||
onClick={() => {
|
closeDropdown();
|
||||||
closeDropdown();
|
}}
|
||||||
openModal(DELETE_ACCOUNT_MODAL_ID);
|
/>
|
||||||
}}
|
{account.authFailedAt && (
|
||||||
/>
|
<MenuItem
|
||||||
</DropdownMenuItemsContainer>
|
LeftIcon={IconRefresh}
|
||||||
|
text={t`Reconnect`}
|
||||||
|
onClick={() => {
|
||||||
|
triggerApisOAuth(account.provider);
|
||||||
|
closeDropdown();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<MenuItem
|
||||||
|
accent="danger"
|
||||||
|
LeftIcon={IconTrash}
|
||||||
|
text={t`Remove account`}
|
||||||
|
onClick={() => {
|
||||||
|
closeDropdown();
|
||||||
|
openModal(DELETE_ACCOUNT_MODAL_ID);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { TextArea } from '@/ui/input/components/TextArea';
|
|||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { ConfigVariableValue } from 'twenty-shared/types';
|
import { ConfigVariableValue } from 'twenty-shared/types';
|
||||||
import { MenuItemMultiSelect } from 'twenty-ui/navigation';
|
import { MenuItemMultiSelect } from 'twenty-ui/navigation';
|
||||||
@ -115,19 +116,21 @@ export const ConfigVariableDatabaseInput = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
{selectOptions.map((option) => (
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItemMultiSelect
|
{selectOptions.map((option) => (
|
||||||
key={option.value}
|
<MenuItemMultiSelect
|
||||||
text={option.label}
|
key={option.value}
|
||||||
selected={isValueSelected(option.value)}
|
text={option.label}
|
||||||
className="config-variable-array-menu-item-multi-select"
|
selected={isValueSelected(option.value)}
|
||||||
onSelectChange={() =>
|
className="config-variable-array-menu-item-multi-select"
|
||||||
handleMultiSelectChange(option.value)
|
onSelectChange={() =>
|
||||||
}
|
handleMultiSelectChange(option.value)
|
||||||
/>
|
}
|
||||||
))}
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
))}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { ConfigVariableSourceOptions } from '@/settings/admin-panel/config-varia
|
|||||||
import { ConfigVariableFilterCategory } from '@/settings/admin-panel/config-variables/types/ConfigVariableFilterCategory';
|
import { ConfigVariableFilterCategory } from '@/settings/admin-panel/config-variables/types/ConfigVariableFilterCategory';
|
||||||
import { ConfigVariableGroupFilter } from '@/settings/admin-panel/config-variables/types/ConfigVariableGroupFilter';
|
import { ConfigVariableGroupFilter } from '@/settings/admin-panel/config-variables/types/ConfigVariableGroupFilter';
|
||||||
import { ConfigVariableSourceFilter } from '@/settings/admin-panel/config-variables/types/ConfigVariableSourceFilter';
|
import { ConfigVariableSourceFilter } from '@/settings/admin-panel/config-variables/types/ConfigVariableSourceFilter';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -48,7 +49,7 @@ export const ConfigVariableOptionsDropdownContent = ({
|
|||||||
|
|
||||||
if (!selectedCategory) {
|
if (!selectedCategory) {
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItemSelectTag
|
<MenuItemSelectTag
|
||||||
text={t`Source`}
|
text={t`Source`}
|
||||||
@ -85,12 +86,12 @@ export const ConfigVariableOptionsDropdownContent = ({
|
|||||||
onClick={() => onShowHiddenChange(!showHiddenGroupVariables)}
|
onClick={() => onShowHiddenChange(!showHiddenGroupVariables)}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -136,6 +137,6 @@ export const ConfigVariableOptionsDropdownContent = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
|
import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLocation, useParams, useSearchParams } from 'react-router-dom';
|
|
||||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { useLocation, useParams, useSearchParams } from 'react-router-dom';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { Button } from 'twenty-ui/input';
|
|
||||||
import { IconChevronDown } from 'twenty-ui/display';
|
import { IconChevronDown } from 'twenty-ui/display';
|
||||||
|
import { Button } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -110,7 +110,7 @@ export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
|
|||||||
</StyledButtonContainer>
|
</StyledButtonContainer>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenu>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<StyledMenuItemWrapper>
|
<StyledMenuItemWrapper>
|
||||||
<StyledMenuItem
|
<StyledMenuItem
|
||||||
@ -128,7 +128,7 @@ export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
|
|||||||
/>
|
/>
|
||||||
</StyledMenuItemWrapper>
|
</StyledMenuItemWrapper>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -3,13 +3,12 @@ import { AdvancedSettingsWrapper } from '@/settings/components/AdvancedSettingsW
|
|||||||
import { OPTION_VALUE_MAXIMUM_LENGTH } from '@/settings/data-model/constants/OptionValueMaximumLength';
|
import { OPTION_VALUE_MAXIMUM_LENGTH } from '@/settings/data-model/constants/OptionValueMaximumLength';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
|
||||||
import {
|
import {
|
||||||
ColorSample,
|
ColorSample,
|
||||||
IconCheck,
|
IconCheck,
|
||||||
@ -19,8 +18,9 @@ import {
|
|||||||
IconX,
|
IconX,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
import { MAIN_COLOR_NAMES } from 'twenty-ui/theme';
|
|
||||||
import { MenuItem, MenuItemSelectColor } from 'twenty-ui/navigation';
|
import { MenuItem, MenuItemSelectColor } from 'twenty-ui/navigation';
|
||||||
|
import { MAIN_COLOR_NAMES } from 'twenty-ui/theme';
|
||||||
|
import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||||
|
|
||||||
type SettingsDataModelFieldSelectFormOptionRowProps = {
|
type SettingsDataModelFieldSelectFormOptionRowProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -120,19 +120,21 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
|||||||
dropdownHotkeyScope={{ scope: SELECT_COLOR_DROPDOWN_ID }}
|
dropdownHotkeyScope={{ scope: SELECT_COLOR_DROPDOWN_ID }}
|
||||||
clickableComponent={<StyledColorSample colorName={option.color} />}
|
clickableComponent={<StyledColorSample colorName={option.color} />}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
{MAIN_COLOR_NAMES.map((colorName) => (
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItemSelectColor
|
{MAIN_COLOR_NAMES.map((colorName) => (
|
||||||
key={colorName}
|
<MenuItemSelectColor
|
||||||
onClick={() => {
|
key={colorName}
|
||||||
onChange({ ...option, color: colorName });
|
onClick={() => {
|
||||||
closeColorDropdown();
|
onChange({ ...option, color: colorName });
|
||||||
}}
|
closeColorDropdown();
|
||||||
color={colorName}
|
}}
|
||||||
selected={colorName === option.color}
|
color={colorName}
|
||||||
/>
|
selected={colorName === option.color}
|
||||||
))}
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
))}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StyledOptionInput
|
<StyledOptionInput
|
||||||
@ -163,7 +165,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
|||||||
<StyledLightIconButton accent="tertiary" Icon={IconDotsVertical} />
|
<StyledLightIconButton accent="tertiary" Icon={IconDotsVertical} />
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenu>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{isDefault ? (
|
{isDefault ? (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@ -196,7 +198,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import {
|
import {
|
||||||
IconArchive,
|
IconArchive,
|
||||||
@ -55,29 +57,30 @@ export const SettingsObjectFieldActiveActionDropdown = ({
|
|||||||
accent="tertiary"
|
accent="tertiary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text={isCustomField ? 'Edit' : 'View'}
|
|
||||||
LeftIcon={isCustomField ? IconPencil : IconEye}
|
|
||||||
onClick={handleEdit}
|
|
||||||
/>
|
|
||||||
{!!onSetAsLabelIdentifier && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text="Set as record text"
|
text={isCustomField ? 'Edit' : 'View'}
|
||||||
LeftIcon={IconTextSize}
|
LeftIcon={isCustomField ? IconPencil : IconEye}
|
||||||
onClick={handleSetAsLabelIdentifier}
|
onClick={handleEdit}
|
||||||
/>
|
/>
|
||||||
)}
|
{!!onSetAsLabelIdentifier && (
|
||||||
{!!onDeactivate && (
|
<MenuItem
|
||||||
<MenuItem
|
text="Set as record text"
|
||||||
text="Deactivate"
|
LeftIcon={IconTextSize}
|
||||||
LeftIcon={IconArchive}
|
onClick={handleSetAsLabelIdentifier}
|
||||||
onClick={handleDeactivate}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
{!!onDeactivate && (
|
||||||
</DropdownMenuItemsContainer>
|
<MenuItem
|
||||||
|
text="Deactivate"
|
||||||
|
LeftIcon={IconArchive}
|
||||||
|
onClick={handleDeactivate}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import {
|
import {
|
||||||
@ -60,28 +62,29 @@ export const SettingsObjectFieldInactiveActionDropdown = ({
|
|||||||
accent="tertiary"
|
accent="tertiary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text={isCustomField ? t`Edit` : t`View`}
|
|
||||||
LeftIcon={isCustomField ? IconPencil : IconEye}
|
|
||||||
onClick={handleEdit}
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text={t`Activate`}
|
|
||||||
LeftIcon={IconArchiveOff}
|
|
||||||
onClick={handleActivate}
|
|
||||||
/>
|
|
||||||
{isDeletable && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={t`Delete`}
|
text={isCustomField ? t`Edit` : t`View`}
|
||||||
accent="danger"
|
LeftIcon={isCustomField ? IconPencil : IconEye}
|
||||||
LeftIcon={IconTrash}
|
onClick={handleEdit}
|
||||||
onClick={handleDelete}
|
|
||||||
/>
|
/>
|
||||||
)}
|
<MenuItem
|
||||||
</DropdownMenuItemsContainer>
|
text={t`Activate`}
|
||||||
|
LeftIcon={IconArchiveOff}
|
||||||
|
onClick={handleActivate}
|
||||||
|
/>
|
||||||
|
{isDeletable && (
|
||||||
|
<MenuItem
|
||||||
|
text={t`Delete`}
|
||||||
|
accent="danger"
|
||||||
|
LeftIcon={IconTrash}
|
||||||
|
onClick={handleDelete}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{
|
dropdownHotkeyScope={{
|
||||||
scope: dropdownId,
|
scope: dropdownId,
|
||||||
|
|||||||
@ -1,103 +0,0 @@
|
|||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|
||||||
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
|
|
||||||
import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag';
|
|
||||||
import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|
||||||
import {
|
|
||||||
IconArchive,
|
|
||||||
IconDotsVertical,
|
|
||||||
IconPencil,
|
|
||||||
useIcons,
|
|
||||||
} from 'twenty-ui/display';
|
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
type SettingsObjectSummaryCardProps = {
|
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
|
||||||
iconKey?: string;
|
|
||||||
name: string;
|
|
||||||
onDeactivate: () => void;
|
|
||||||
onEdit: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledObjectTypeTag = styled(SettingsDataModelObjectTypeTag)`
|
|
||||||
box-sizing: border-box;
|
|
||||||
height: ${({ theme }) => theme.spacing(6)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const dropdownId = 'settings-object-edit-about-menu-dropdown';
|
|
||||||
|
|
||||||
export const SettingsObjectSummaryCard = ({
|
|
||||||
objectMetadataItem,
|
|
||||||
iconKey = '',
|
|
||||||
name,
|
|
||||||
onDeactivate,
|
|
||||||
onEdit,
|
|
||||||
}: SettingsObjectSummaryCardProps) => {
|
|
||||||
const theme = useTheme();
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
const Icon = getIcon(iconKey);
|
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(dropdownId);
|
|
||||||
|
|
||||||
const handleEdit = () => {
|
|
||||||
onEdit();
|
|
||||||
closeDropdown();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeactivate = () => {
|
|
||||||
onDeactivate();
|
|
||||||
closeDropdown();
|
|
||||||
};
|
|
||||||
|
|
||||||
const objectTypeLabel = getObjectTypeLabel(objectMetadataItem);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingsSummaryCard
|
|
||||||
title={
|
|
||||||
<>
|
|
||||||
{!!Icon && <Icon size={theme.icon.size.md} />}
|
|
||||||
{name}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
rightComponent={
|
|
||||||
<>
|
|
||||||
<StyledObjectTypeTag objectTypeLabel={objectTypeLabel} />
|
|
||||||
<Dropdown
|
|
||||||
dropdownId={dropdownId}
|
|
||||||
clickableComponent={
|
|
||||||
<LightIconButton
|
|
||||||
aria-label="Object Options"
|
|
||||||
Icon={IconDotsVertical}
|
|
||||||
accent="tertiary"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
<MenuItem
|
|
||||||
text="Edit"
|
|
||||||
LeftIcon={IconPencil}
|
|
||||||
onClick={handleEdit}
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
text="Deactivate"
|
|
||||||
LeftIcon={IconArchive}
|
|
||||||
onClick={handleDeactivate}
|
|
||||||
/>
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
}
|
|
||||||
dropdownHotkeyScope={{
|
|
||||||
scope: dropdownId,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,5 +1,7 @@
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { IconArchiveOff, IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
import { IconArchiveOff, IconDotsVertical, IconTrash } from 'twenty-ui/display';
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
@ -42,23 +44,24 @@ export const SettingsObjectInactiveMenuDropDown = ({
|
|||||||
accent="tertiary"
|
accent="tertiary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text="Activate"
|
|
||||||
LeftIcon={IconArchiveOff}
|
|
||||||
onClick={handleActivate}
|
|
||||||
/>
|
|
||||||
{isCustomObject && (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text="Delete"
|
text="Activate"
|
||||||
LeftIcon={IconTrash}
|
LeftIcon={IconArchiveOff}
|
||||||
accent="danger"
|
onClick={handleActivate}
|
||||||
onClick={handleDelete}
|
|
||||||
/>
|
/>
|
||||||
)}
|
{isCustomObject && (
|
||||||
</DropdownMenuItemsContainer>
|
<MenuItem
|
||||||
|
text="Delete"
|
||||||
|
LeftIcon={IconTrash}
|
||||||
|
accent="danger"
|
||||||
|
onClick={handleDelete}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
|
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
|
||||||
import { SettingsIntegrationDatabaseConnectionSyncStatus } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus';
|
import { SettingsIntegrationDatabaseConnectionSyncStatus } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { IconDotsVertical, IconPencil, IconTrash } from 'twenty-ui/display';
|
import { IconDotsVertical, IconPencil, IconTrash } from 'twenty-ui/display';
|
||||||
@ -58,16 +59,18 @@ export const SettingsIntegrationDatabaseConnectionSummaryCard = ({
|
|||||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
LeftIcon={IconTrash}
|
<MenuItem
|
||||||
text="Remove"
|
LeftIcon={IconTrash}
|
||||||
onClick={onRemove}
|
text="Remove"
|
||||||
/>
|
onClick={onRemove}
|
||||||
<UndecoratedLink to="./edit">
|
/>
|
||||||
<MenuItem LeftIcon={IconPencil} text="Edit" />
|
<UndecoratedLink to="./edit">
|
||||||
</UndecoratedLink>
|
<MenuItem LeftIcon={IconPencil} text="Edit" />
|
||||||
</DropdownMenuItemsContainer>
|
</UndecoratedLink>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useObjectRecordSearchRecords } from '@/object-record/hooks/useObjectRecordSearchRecords';
|
import { useObjectRecordSearchRecords } from '@/object-record/hooks/useObjectRecordSearchRecords';
|
||||||
import { SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent';
|
import { SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
@ -38,7 +38,7 @@ export const SettingsRoleAssignmentWorkspaceMemberPickerDropdown = ({
|
|||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownContent>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={handleSearchFilterChange}
|
onChange={handleSearchFilterChange}
|
||||||
@ -53,6 +53,6 @@ export const SettingsRoleAssignmentWorkspaceMemberPickerDropdown = ({
|
|||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
@ -37,7 +37,7 @@ export const SettingsRolePermissionsObjectLevelObjectPickerDropdownContent = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownContent>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={handleSearchFilterChange}
|
onChange={handleSearchFilterChange}
|
||||||
@ -54,6 +54,6 @@ export const SettingsRolePermissionsObjectLevelObjectPickerDropdownContent = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdent
|
|||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
@ -72,28 +73,29 @@ export const SettingsSecuritySSORowDropdownMenu = ({
|
|||||||
clickableComponent={
|
clickableComponent={
|
||||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
accent="default"
|
<MenuItem
|
||||||
LeftIcon={IconArchive}
|
accent="default"
|
||||||
text={SSOIdp.status === 'Active' ? t`Deactivate` : t`Activate`}
|
LeftIcon={IconArchive}
|
||||||
onClick={() => {
|
text={SSOIdp.status === 'Active' ? t`Deactivate` : t`Activate`}
|
||||||
toggleSSOIdentityProviderStatus(SSOIdp.id);
|
onClick={() => {
|
||||||
closeDropdown();
|
toggleSSOIdentityProviderStatus(SSOIdp.id);
|
||||||
}}
|
closeDropdown();
|
||||||
/>
|
}}
|
||||||
<MenuItem
|
/>
|
||||||
accent="danger"
|
<MenuItem
|
||||||
LeftIcon={IconTrash}
|
accent="danger"
|
||||||
text={t`Delete`}
|
LeftIcon={IconTrash}
|
||||||
onClick={() => {
|
text={t`Delete`}
|
||||||
handleDeleteSSOIdentityProvider(SSOIdp.id);
|
onClick={() => {
|
||||||
closeDropdown();
|
handleDeleteSSOIdentityProvider(SSOIdp.id);
|
||||||
}}
|
closeDropdown();
|
||||||
/>
|
}}
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { approvedAccessDomainsState } from '@/settings/security/states/ApprovedA
|
|||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { UnwrapRecoilValue, useSetRecoilState } from 'recoil';
|
import { UnwrapRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
@ -61,19 +62,20 @@ export const SettingsSecurityApprovedAccessDomainRowDropdownMenu = ({
|
|||||||
clickableComponent={
|
clickableComponent={
|
||||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
}
|
}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
accent="danger"
|
<MenuItem
|
||||||
LeftIcon={IconTrash}
|
accent="danger"
|
||||||
text="Delete"
|
LeftIcon={IconTrash}
|
||||||
onClick={() => {
|
text="Delete"
|
||||||
handleDeleteApprovedAccessDomain();
|
onClick={() => {
|
||||||
closeDropdown();
|
handleDeleteApprovedAccessDomain();
|
||||||
}}
|
closeDropdown();
|
||||||
/>
|
}}
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { EnvironmentVariable } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariablesSection';
|
import { EnvironmentVariable } from '@/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTabEnvironmentVariablesSection';
|
||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
@ -109,24 +110,26 @@ export const SettingsServerlessFunctionTabEnvironmentVariableTableRow = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text={'Edit'}
|
<MenuItem
|
||||||
LeftIcon={IconPencil}
|
text={'Edit'}
|
||||||
onClick={() => {
|
LeftIcon={IconPencil}
|
||||||
setEditMode(true);
|
onClick={() => {
|
||||||
closeDropdown();
|
setEditMode(true);
|
||||||
}}
|
closeDropdown();
|
||||||
/>
|
}}
|
||||||
<MenuItem
|
/>
|
||||||
text={'Delete'}
|
<MenuItem
|
||||||
LeftIcon={IconTrash}
|
text={'Delete'}
|
||||||
onClick={() => {
|
LeftIcon={IconTrash}
|
||||||
onDelete();
|
onClick={() => {
|
||||||
closeDropdown();
|
onDelete();
|
||||||
}}
|
closeDropdown();
|
||||||
/>
|
}}
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropDownId }}
|
dropdownHotkeyScope={{ scope: dropDownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
|||||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||||
import { DO_NOT_IMPORT_OPTION_KEY } from '@/spreadsheet-import/constants/DoNotImportOptionKey';
|
import { DO_NOT_IMPORT_OPTION_KEY } from '@/spreadsheet-import/constants/DoNotImportOptionKey';
|
||||||
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
|
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -59,7 +60,7 @@ export const MatchColumnSelectFieldSelectDropdownContent = ({
|
|||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -76,7 +77,7 @@ export const MatchColumnSelectFieldSelectDropdownContent = ({
|
|||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItemsContainer hasMaxHeight width={200}>
|
<DropdownMenuItemsContainer hasMaxHeight>
|
||||||
<MenuItemSelect
|
<MenuItemSelect
|
||||||
selected={selectedValue?.value === DO_NOT_IMPORT_OPTION_KEY}
|
selected={selectedValue?.value === DO_NOT_IMPORT_OPTION_KEY}
|
||||||
onClick={onDoNotImportSelect}
|
onClick={onDoNotImportSelect}
|
||||||
@ -98,6 +99,6 @@ export const MatchColumnSelectFieldSelectDropdownContent = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
|||||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||||
import { getSubFieldOptionKey } from '@/object-record/spreadsheet-import/utils/getSubFieldOptionKey';
|
import { getSubFieldOptionKey } from '@/object-record/spreadsheet-import/utils/getSubFieldOptionKey';
|
||||||
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -68,7 +69,7 @@ export const MatchColumnSelectSubFieldSelectDropdownContent = ({
|
|||||||
.filter((subFieldName) => subFieldName.includes(searchFilter));
|
.filter((subFieldName) => subFieldName.includes(searchFilter));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -85,7 +86,7 @@ export const MatchColumnSelectSubFieldSelectDropdownContent = ({
|
|||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItemsContainer hasMaxHeight width={200}>
|
<DropdownMenuItemsContainer hasMaxHeight>
|
||||||
{subFieldNamesThatExistInOptions.map((subFieldName) => (
|
{subFieldNamesThatExistInOptions.map((subFieldName) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={subFieldName}
|
key={subFieldName}
|
||||||
@ -104,6 +105,6 @@ export const MatchColumnSelectSubFieldSelectDropdownContent = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
@ -48,7 +48,7 @@ export const SubMatchingSelectInput = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu ref={containerRef} data-select-disable>
|
<DropdownContent ref={containerRef}>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(e) => setSearchFilter(e.target.value)}
|
onChange={(e) => setSearchFilter(e.target.value)}
|
||||||
@ -67,6 +67,6 @@ export const SubMatchingSelectInput = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import { SupportButtonSkeletonLoader } from '@/support/components/SupportButtonS
|
|||||||
import { useSupportChat } from '@/support/hooks/useSupportChat';
|
import { useSupportChat } from '@/support/hooks/useSupportChat';
|
||||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Button, LightIconButton } from 'twenty-ui/input';
|
|
||||||
import { IconHelpCircle } from 'twenty-ui/display';
|
import { IconHelpCircle } from 'twenty-ui/display';
|
||||||
|
import { Button, LightIconButton } from 'twenty-ui/input';
|
||||||
|
|
||||||
const StyledButtonContainer = styled.div`
|
const StyledButtonContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { SupportButton } from '@/support/components/SupportButton';
|
import { SupportButton } from '@/support/components/SupportButton';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { IconHelpCircle, IconMessage } from 'twenty-ui/display';
|
import { IconHelpCircle, IconMessage } from 'twenty-ui/display';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
@ -26,20 +28,21 @@ export const SupportDropdown = () => {
|
|||||||
dropdownPlacement="top-start"
|
dropdownPlacement="top-start"
|
||||||
dropdownOffset={{ x: 0, y: -28 }}
|
dropdownOffset={{ x: 0, y: -28 }}
|
||||||
clickableComponent={<SupportButton />}
|
clickableComponent={<SupportButton />}
|
||||||
dropdownWidth={160}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.Narrow}>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
text="Talk to us"
|
<MenuItem
|
||||||
LeftIcon={IconMessage}
|
text="Talk to us"
|
||||||
onClick={handleTalkToUs}
|
LeftIcon={IconMessage}
|
||||||
/>
|
onClick={handleTalkToUs}
|
||||||
<MenuItem
|
/>
|
||||||
text="Documentation"
|
<MenuItem
|
||||||
LeftIcon={IconHelpCircle}
|
text="Documentation"
|
||||||
onClick={handleUserGuide}
|
LeftIcon={IconHelpCircle}
|
||||||
/>
|
onClick={handleUserGuide}
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -2,12 +2,12 @@ import { useRef, useState } from 'react';
|
|||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
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';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
|
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
@ -102,7 +102,7 @@ export const MultiSelectInput = ({
|
|||||||
selectableItemIdArray={optionIds}
|
selectableItemIdArray={optionIds}
|
||||||
hotkeyScope={hotkeyScope}
|
hotkeyScope={hotkeyScope}
|
||||||
>
|
>
|
||||||
<DropdownMenu data-select-disable ref={containerRef}>
|
<DropdownContent ref={containerRef} selectDisabled>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -130,7 +130,7 @@ export const MultiSelectInput = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import styled from '@emotion/styled';
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
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';
|
||||||
@ -11,6 +10,8 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
|
|||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
import { arrayToChunks } from '~/utils/array/arrayToChunks';
|
import { arrayToChunks } from '~/utils/array/arrayToChunks';
|
||||||
|
|
||||||
|
import { ICON_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/ui/input/components/constants/IconPickerDropdownContentWidth';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { useSelectableListListenToEnterHotkeyOnItem } from '@/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem';
|
import { useSelectableListListenToEnterHotkeyOnItem } from '@/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem';
|
||||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -179,14 +180,13 @@ export const IconPicker = ({
|
|||||||
size={size}
|
size={size}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownWidth={176}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<SelectableList
|
<DropdownContent widthInPixels={ICON_PICKER_DROPDOWN_CONTENT_WIDTH}>
|
||||||
selectableListInstanceId="icon-list"
|
<SelectableList
|
||||||
selectableItemIdMatrix={iconKeys2d}
|
selectableListInstanceId="icon-list"
|
||||||
hotkeyScope={IconPickerHotkeyScope.IconPicker}
|
selectableItemIdMatrix={iconKeys2d}
|
||||||
>
|
hotkeyScope={IconPickerHotkeyScope.IconPicker}
|
||||||
<DropdownMenu width={176}>
|
>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
placeholder={t`Search icon`}
|
placeholder={t`Search icon`}
|
||||||
autoFocus
|
autoFocus
|
||||||
@ -220,8 +220,8 @@ export const IconPicker = ({
|
|||||||
</StyledMenuIconItemsContainer>
|
</StyledMenuIconItemsContainer>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenu>
|
</SelectableList>
|
||||||
</SelectableList>
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
|||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
|
||||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
|
import { DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||||
@ -67,7 +69,7 @@ export const Select = <Value extends SelectValue>({
|
|||||||
disabled: disabledFromProps,
|
disabled: disabledFromProps,
|
||||||
selectSizeVariant,
|
selectSizeVariant,
|
||||||
dropdownId,
|
dropdownId,
|
||||||
dropdownWidth = 176,
|
dropdownWidth = GenericDropdownContentWidth.Medium,
|
||||||
dropdownWidthAuto = false,
|
dropdownWidthAuto = false,
|
||||||
emptyOption,
|
emptyOption,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
@ -139,7 +141,6 @@ export const Select = <Value extends SelectValue>({
|
|||||||
) : (
|
) : (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
dropdownWidth={dropDownMenuWidth}
|
|
||||||
dropdownPlacement="bottom-start"
|
dropdownPlacement="bottom-start"
|
||||||
dropdownOffset={dropdownOffset}
|
dropdownOffset={dropdownOffset}
|
||||||
clickableComponent={
|
clickableComponent={
|
||||||
@ -151,7 +152,7 @@ export const Select = <Value extends SelectValue>({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<>
|
<DropdownContent widthInPixels={dropDownMenuWidth}>
|
||||||
{!!withSearchInput && (
|
{!!withSearchInput && (
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
autoFocus
|
autoFocus
|
||||||
@ -163,7 +164,7 @@ export const Select = <Value extends SelectValue>({
|
|||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
)}
|
)}
|
||||||
{!!filteredOptions.length && (
|
{!!filteredOptions.length && (
|
||||||
<DropdownMenuItemsContainer hasMaxHeight width={'auto'}>
|
<DropdownMenuItemsContainer hasMaxHeight>
|
||||||
<SelectableList
|
<SelectableList
|
||||||
hotkeyScope={SelectHotkeyScope.Select}
|
hotkeyScope={SelectHotkeyScope.Select}
|
||||||
selectableListInstanceId={dropdownId}
|
selectableListInstanceId={dropdownId}
|
||||||
@ -208,7 +209,7 @@ export const Select = <Value extends SelectValue>({
|
|||||||
/>
|
/>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
)}
|
)}
|
||||||
</>
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
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';
|
||||||
@ -96,7 +96,7 @@ export const SelectInput = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu ref={containerRef} data-select-disable>
|
<DropdownContent ref={containerRef} selectDisabled>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(e) => setSearchFilter(e.target.value)}
|
onChange={(e) => setSearchFilter(e.target.value)}
|
||||||
@ -129,6 +129,6 @@ export const SelectInput = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const ICON_PICKER_DROPDOWN_CONTENT_WIDTH = 176;
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
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';
|
||||||
|
|
||||||
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
||||||
import { Currency } from '@/ui/input/components/internal/types/Currency';
|
import { Currency } from '@/ui/input/components/internal/types/Currency';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation';
|
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
export const CurrencyPickerDropdownSelect = ({
|
export const CurrencyPickerDropdownSelect = ({
|
||||||
@ -31,7 +31,7 @@ export const CurrencyPickerDropdownSelect = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownContent>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(event) => setSearchFilter(event.target.value)}
|
onChange={(event) => setSearchFilter(event.target.value)}
|
||||||
@ -65,6 +65,6 @@ export const CurrencyPickerDropdownSelect = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
|||||||
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';
|
||||||
|
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import 'react-phone-number-input/style.css';
|
import 'react-phone-number-input/style.css';
|
||||||
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation';
|
import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ export const PhoneCountryPickerDropdownSelect = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(event) => setSearchFilter(event.currentTarget.value)}
|
onChange={(event) => setSearchFilter(event.currentTarget.value)}
|
||||||
@ -90,6 +91,6 @@ export const PhoneCountryPickerDropdownSelect = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { SuggestionMenuProps } from '@blocknote/react';
|
import { SuggestionMenuProps } from '@blocknote/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||||
import { autoUpdate, useFloating } from '@floating-ui/react';
|
import { autoUpdate, useFloating } from '@floating-ui/react';
|
||||||
@ -46,7 +46,7 @@ export const CustomSlashMenu = (props: CustomSlashMenuProps) => {
|
|||||||
>
|
>
|
||||||
<OverlayContainer ref={refs.setFloating} style={floatingStyles}>
|
<OverlayContainer ref={refs.setFloating} style={floatingStyles}>
|
||||||
<StyledInnerContainer>
|
<StyledInnerContainer>
|
||||||
<DropdownMenu style={{ zIndex: 2001 }}>
|
<DropdownContent>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{props.items.map((item, index) => (
|
{props.items.map((item, index) => (
|
||||||
<MenuItemSuggestion
|
<MenuItemSuggestion
|
||||||
@ -58,7 +58,7 @@ export const CustomSlashMenu = (props: CustomSlashMenuProps) => {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</StyledInnerContainer>
|
</StyledInnerContainer>
|
||||||
</OverlayContainer>
|
</OverlayContainer>
|
||||||
</motion.div>,
|
</motion.div>,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
|
||||||
import { DropdownOnToggleEffect } from '@/ui/layout/dropdown/components/DropdownOnToggleEffect';
|
import { DropdownOnToggleEffect } from '@/ui/layout/dropdown/components/DropdownOnToggleEffect';
|
||||||
|
import { DropdownInternalContainer } from '@/ui/layout/dropdown/components/internal/DropdownInternalContainer';
|
||||||
import { DROPDOWN_RESIZE_MIN_HEIGHT } from '@/ui/layout/dropdown/constants/DropdownResizeMinHeight';
|
import { DROPDOWN_RESIZE_MIN_HEIGHT } from '@/ui/layout/dropdown/constants/DropdownResizeMinHeight';
|
||||||
import { DROPDOWN_RESIZE_MIN_WIDTH } from '@/ui/layout/dropdown/constants/DropdownResizeMinWidth';
|
import { DROPDOWN_RESIZE_MIN_WIDTH } from '@/ui/layout/dropdown/constants/DropdownResizeMinWidth';
|
||||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
|
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
|
||||||
@ -52,18 +52,17 @@ export type DropdownProps = {
|
|||||||
dropdownHotkeyScope: HotkeyScope;
|
dropdownHotkeyScope: HotkeyScope;
|
||||||
dropdownId: string;
|
dropdownId: string;
|
||||||
dropdownPlacement?: Placement;
|
dropdownPlacement?: Placement;
|
||||||
dropdownWidth?: Width;
|
|
||||||
dropdownOffset?: DropdownOffset;
|
dropdownOffset?: DropdownOffset;
|
||||||
dropdownStrategy?: 'fixed' | 'absolute';
|
dropdownStrategy?: 'fixed' | 'absolute';
|
||||||
onClickOutside?: () => void;
|
onClickOutside?: () => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
onOpen?: () => void;
|
onOpen?: () => void;
|
||||||
|
excludedClickOutsideIds?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Dropdown = ({
|
export const Dropdown = ({
|
||||||
clickableComponent,
|
clickableComponent,
|
||||||
dropdownComponents,
|
dropdownComponents,
|
||||||
dropdownWidth,
|
|
||||||
hotkey,
|
hotkey,
|
||||||
dropdownId,
|
dropdownId,
|
||||||
dropdownHotkeyScope,
|
dropdownHotkeyScope,
|
||||||
@ -74,6 +73,7 @@ export const Dropdown = ({
|
|||||||
onClose,
|
onClose,
|
||||||
onOpen,
|
onOpen,
|
||||||
clickableComponentWidth = 'auto',
|
clickableComponentWidth = 'auto',
|
||||||
|
excludedClickOutsideIds,
|
||||||
}: DropdownProps) => {
|
}: DropdownProps) => {
|
||||||
const { isDropdownOpen, toggleDropdown } = useDropdown(dropdownId);
|
const { isDropdownOpen, toggleDropdown } = useDropdown(dropdownId);
|
||||||
|
|
||||||
@ -182,9 +182,8 @@ export const Dropdown = ({
|
|||||||
<StyledDropdownFallbackAnchor ref={refs.setReference} />
|
<StyledDropdownFallbackAnchor ref={refs.setReference} />
|
||||||
)}
|
)}
|
||||||
{isDropdownOpen && (
|
{isDropdownOpen && (
|
||||||
<DropdownContent
|
<DropdownInternalContainer
|
||||||
floatingStyles={floatingStyles}
|
floatingStyles={floatingStyles}
|
||||||
dropdownWidth={dropdownWidth}
|
|
||||||
dropdownComponents={dropdownComponents}
|
dropdownComponents={dropdownComponents}
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
dropdownPlacement={placement}
|
dropdownPlacement={placement}
|
||||||
@ -193,6 +192,7 @@ export const Dropdown = ({
|
|||||||
hotkey={hotkey}
|
hotkey={hotkey}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
onHotkeyTriggered={toggleDropdown}
|
onHotkeyTriggered={toggleDropdown}
|
||||||
|
excludedClickOutsideIds={excludedClickOutsideIds}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<DropdownOnToggleEffect
|
<DropdownOnToggleEffect
|
||||||
|
|||||||
@ -1,149 +1,37 @@
|
|||||||
import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices';
|
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|
||||||
import { useInternalHotkeyScopeManagement } from '@/ui/layout/dropdown/hooks/useInternalHotkeyScopeManagement';
|
|
||||||
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
|
||||||
import { dropdownMaxHeightComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState';
|
|
||||||
import { dropdownMaxWidthComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState';
|
|
||||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
|
||||||
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
|
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
|
||||||
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
|
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import {
|
import { Ref, forwardRef } from 'react';
|
||||||
FloatingPortal,
|
|
||||||
Placement,
|
|
||||||
UseFloatingReturn,
|
|
||||||
} from '@floating-ui/react';
|
|
||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import { Keys } from 'react-hotkeys-hook';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { Key } from 'ts-key-enum';
|
|
||||||
|
|
||||||
export const StyledDropdownContentContainer = styled.div`
|
const StyledInternalBaseDropdownContent = styled.div<{
|
||||||
|
widthInPixels: number;
|
||||||
|
}>`
|
||||||
display: flex;
|
display: flex;
|
||||||
z-index: ${RootStackingContextZIndices.DropdownPortal};
|
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
width: ${({ widthInPixels }) => widthInPixels}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export type DropdownContentProps = {
|
export const DropdownContent = forwardRef(
|
||||||
dropdownId: string;
|
(
|
||||||
dropdownPlacement: Placement;
|
{
|
||||||
floatingUiRefs: UseFloatingReturn['refs'];
|
children,
|
||||||
onClickOutside?: () => void;
|
widthInPixels = GenericDropdownContentWidth.Medium,
|
||||||
hotkeyScope: HotkeyScope;
|
selectDisabled = false,
|
||||||
floatingStyles: UseFloatingReturn['floatingStyles'];
|
}: React.PropsWithChildren<{
|
||||||
hotkey?: {
|
widthInPixels?: number;
|
||||||
key: Keys;
|
selectDisabled?: boolean;
|
||||||
scope: string;
|
}>,
|
||||||
};
|
ref: Ref<HTMLDivElement>,
|
||||||
onHotkeyTriggered?: () => void;
|
) => {
|
||||||
dropdownWidth?: `${string}px` | `${number}%` | 'auto' | number;
|
return (
|
||||||
dropdownComponents: React.ReactNode;
|
<StyledInternalBaseDropdownContent
|
||||||
parentDropdownId?: string;
|
data-select-disable={selectDisabled}
|
||||||
};
|
widthInPixels={widthInPixels}
|
||||||
|
ref={ref}
|
||||||
export const DropdownContent = ({
|
>
|
||||||
dropdownId,
|
{children}
|
||||||
dropdownPlacement,
|
</StyledInternalBaseDropdownContent>
|
||||||
floatingUiRefs,
|
);
|
||||||
onClickOutside,
|
},
|
||||||
hotkeyScope,
|
);
|
||||||
floatingStyles,
|
|
||||||
hotkey,
|
|
||||||
onHotkeyTriggered,
|
|
||||||
dropdownWidth,
|
|
||||||
dropdownComponents,
|
|
||||||
}: DropdownContentProps) => {
|
|
||||||
const { isDropdownOpen, closeDropdown, setDropdownPlacement } =
|
|
||||||
useDropdown(dropdownId);
|
|
||||||
|
|
||||||
const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState);
|
|
||||||
|
|
||||||
const dropdownMaxHeight = useRecoilComponentValueV2(
|
|
||||||
dropdownMaxHeightComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const dropdownMaxWidth = useRecoilComponentValueV2(
|
|
||||||
dropdownMaxWidthComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setDropdownPlacement(dropdownPlacement);
|
|
||||||
}, [dropdownPlacement, setDropdownPlacement]);
|
|
||||||
|
|
||||||
useListenClickOutside({
|
|
||||||
refs: [floatingUiRefs.floating, floatingUiRefs.domReference],
|
|
||||||
listenerId: dropdownId,
|
|
||||||
callback: (event) => {
|
|
||||||
if (activeDropdownFocusId !== dropdownId) return;
|
|
||||||
|
|
||||||
if (isDropdownOpen) {
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
closeDropdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickOutside?.();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
useInternalHotkeyScopeManagement({
|
|
||||||
dropdownScopeId: dropdownId,
|
|
||||||
dropdownHotkeyScopeFromParent: hotkeyScope,
|
|
||||||
});
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
[Key.Escape],
|
|
||||||
() => {
|
|
||||||
if (activeDropdownFocusId !== dropdownId) return;
|
|
||||||
|
|
||||||
if (isDropdownOpen) {
|
|
||||||
closeDropdown();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hotkeyScope?.scope,
|
|
||||||
[closeDropdown, isDropdownOpen],
|
|
||||||
);
|
|
||||||
|
|
||||||
const dropdownMenuStyles = {
|
|
||||||
...floatingStyles,
|
|
||||||
maxHeight: dropdownMaxHeight,
|
|
||||||
maxWidth: dropdownMaxWidth,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { excludedClickOutsideId } = useContext(ClickOutsideListenerContext);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{hotkey && onHotkeyTriggered && (
|
|
||||||
<HotkeyEffect hotkey={hotkey} onHotkeyTriggered={onHotkeyTriggered} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<FloatingPortal>
|
|
||||||
<StyledDropdownContentContainer
|
|
||||||
ref={floatingUiRefs.setFloating}
|
|
||||||
style={dropdownMenuStyles}
|
|
||||||
role="listbox"
|
|
||||||
id={`${dropdownId}-options`}
|
|
||||||
data-click-outside-id={excludedClickOutsideId}
|
|
||||||
>
|
|
||||||
<OverlayContainer>
|
|
||||||
<DropdownMenu
|
|
||||||
id={dropdownId}
|
|
||||||
width={dropdownWidth}
|
|
||||||
data-select-disable
|
|
||||||
>
|
|
||||||
{dropdownComponents}
|
|
||||||
</DropdownMenu>
|
|
||||||
</OverlayContainer>
|
|
||||||
</StyledDropdownContentContainer>
|
|
||||||
</FloatingPortal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
import styled from '@emotion/styled';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
|
|
||||||
const StyledDropdownMenu = styled.div<{
|
|
||||||
width?: `${string}px` | `${number}%` | 'auto' | number;
|
|
||||||
}>`
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
width: ${({ width }) =>
|
|
||||||
isDefined(width)
|
|
||||||
? typeof width === 'number'
|
|
||||||
? `${width}px`
|
|
||||||
: width
|
|
||||||
: 'auto'};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const DropdownMenu = StyledDropdownMenu;
|
|
||||||
@ -12,6 +12,9 @@ const StyledHeader = styled.li`
|
|||||||
border-top-left-radius: ${({ theme }) => theme.border.radius.sm};
|
border-top-left-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
border-top-right-radius: ${({ theme }) => theme.border.radius.sm};
|
border-top-right-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
padding: ${({ theme }) => theme.spacing(1)};
|
padding: ${({ theme }) => theme.spacing(1)};
|
||||||
|
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
|
||||||
|
height: ${({ theme }) => theme.spacing(6)};
|
||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { isDefined } from 'twenty-shared/utils';
|
|||||||
|
|
||||||
const StyledDropdownMenuItemsExternalContainer = styled.div<{
|
const StyledDropdownMenuItemsExternalContainer = styled.div<{
|
||||||
hasMaxHeight?: boolean;
|
hasMaxHeight?: boolean;
|
||||||
width: number | 'auto';
|
width: number | 'auto' | '100%';
|
||||||
}>`
|
}>`
|
||||||
--padding: ${({ theme }) => theme.spacing(1)};
|
--padding: ${({ theme }) => theme.spacing(1)};
|
||||||
|
|
||||||
@ -19,10 +19,13 @@ const StyledDropdownMenuItemsExternalContainer = styled.div<{
|
|||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
|
|
||||||
${({ width }) =>
|
${({ width }) =>
|
||||||
isDefined(width) &&
|
isDefined(width) && width === '100%'
|
||||||
css`
|
? css`
|
||||||
width: ${width}px;
|
width: 100%;
|
||||||
`}
|
`
|
||||||
|
: css`
|
||||||
|
width: ${width}px;
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledDropdownMenuItemsInternalContainer = styled.div`
|
const StyledDropdownMenuItemsInternalContainer = styled.div`
|
||||||
@ -31,6 +34,7 @@ const StyledDropdownMenuItemsInternalContainer = styled.div`
|
|||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
@ -39,20 +43,18 @@ const StyledScrollWrapper = styled(ScrollWrapper)`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// TODO: refactor this, the dropdown should handle the max height behavior + scroll with the size middleware
|
|
||||||
// We should instead create a DropdownMenuItemsContainerScrollable or take for granted that it is the default behavior
|
|
||||||
export const DropdownMenuItemsContainer = ({
|
export const DropdownMenuItemsContainer = ({
|
||||||
children,
|
children,
|
||||||
hasMaxHeight,
|
hasMaxHeight,
|
||||||
className,
|
className,
|
||||||
width = 200,
|
|
||||||
scrollable = true,
|
scrollable = true,
|
||||||
|
width = 'auto',
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
hasMaxHeight?: boolean;
|
hasMaxHeight?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
scrollable?: boolean;
|
scrollable?: boolean;
|
||||||
width?: number | 'auto';
|
width?: number | 'auto' | '100%';
|
||||||
}) => {
|
}) => {
|
||||||
const id = useId();
|
const id = useId();
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,6 @@ const meta: Meta<typeof Dropdown> = {
|
|||||||
dropdownHotkeyScope: { scope: 'testDropdownMenu' },
|
dropdownHotkeyScope: { scope: 'testDropdownMenu' },
|
||||||
dropdownOffset: { x: 0, y: 8 },
|
dropdownOffset: { x: 0, y: 8 },
|
||||||
dropdownId: 'test-dropdown-id',
|
dropdownId: 'test-dropdown-id',
|
||||||
dropdownWidth: '200px',
|
|
||||||
},
|
},
|
||||||
argTypes: {
|
argTypes: {
|
||||||
clickableComponent: { control: false },
|
clickableComponent: { control: false },
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
|
|
||||||
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { AVATAR_URL_MOCK, ComponentDecorator } from 'twenty-ui/testing';
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
@ -13,6 +13,7 @@ import {
|
|||||||
IconPlus,
|
IconPlus,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
import { AVATAR_URL_MOCK, ComponentDecorator } from 'twenty-ui/testing';
|
||||||
|
|
||||||
const meta: Meta<typeof DropdownMenuHeader> = {
|
const meta: Meta<typeof DropdownMenuHeader> = {
|
||||||
title: 'UI/Layout/Dropdown/DropdownMenuHeader',
|
title: 'UI/Layout/Dropdown/DropdownMenuHeader',
|
||||||
@ -64,9 +65,11 @@ export const ContextDropdownAndAvatar: Story = {
|
|||||||
dropdownId={'story-dropdown-id-context-menu'}
|
dropdownId={'story-dropdown-id-context-menu'}
|
||||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem LeftIcon={IconPlus} text={`Create Workspace`} />
|
<DropdownMenuItemsContainer>
|
||||||
</DropdownMenuItemsContainer>
|
<MenuItem LeftIcon={IconPlus} text={`Create Workspace`} />
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -0,0 +1,153 @@
|
|||||||
|
import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices';
|
||||||
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
import { useInternalHotkeyScopeManagement } from '@/ui/layout/dropdown/hooks/useInternalHotkeyScopeManagement';
|
||||||
|
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
||||||
|
import { dropdownMaxHeightComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState';
|
||||||
|
import { dropdownMaxWidthComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState';
|
||||||
|
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||||
|
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
|
||||||
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
|
||||||
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import {
|
||||||
|
FloatingPortal,
|
||||||
|
Placement,
|
||||||
|
UseFloatingReturn,
|
||||||
|
} from '@floating-ui/react';
|
||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
import { Keys } from 'react-hotkeys-hook';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
|
export const StyledDropdownContentContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
z-index: ${RootStackingContextZIndices.DropdownPortal};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledDropdownInsideContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type DropdownInternalContainerProps = {
|
||||||
|
dropdownId: string;
|
||||||
|
dropdownPlacement: Placement;
|
||||||
|
floatingUiRefs: UseFloatingReturn['refs'];
|
||||||
|
onClickOutside?: () => void;
|
||||||
|
hotkeyScope: HotkeyScope;
|
||||||
|
floatingStyles: UseFloatingReturn['floatingStyles'];
|
||||||
|
hotkey?: {
|
||||||
|
key: Keys;
|
||||||
|
scope: string;
|
||||||
|
};
|
||||||
|
onHotkeyTriggered?: () => void;
|
||||||
|
dropdownComponents: React.ReactNode;
|
||||||
|
parentDropdownId?: string;
|
||||||
|
excludedClickOutsideIds?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DropdownInternalContainer = ({
|
||||||
|
dropdownId,
|
||||||
|
dropdownPlacement,
|
||||||
|
floatingUiRefs,
|
||||||
|
onClickOutside,
|
||||||
|
hotkeyScope,
|
||||||
|
floatingStyles,
|
||||||
|
hotkey,
|
||||||
|
onHotkeyTriggered,
|
||||||
|
dropdownComponents,
|
||||||
|
excludedClickOutsideIds,
|
||||||
|
}: DropdownInternalContainerProps) => {
|
||||||
|
const { isDropdownOpen, closeDropdown, setDropdownPlacement } =
|
||||||
|
useDropdown(dropdownId);
|
||||||
|
|
||||||
|
const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState);
|
||||||
|
|
||||||
|
const dropdownMaxHeight = useRecoilComponentValueV2(
|
||||||
|
dropdownMaxHeightComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownMaxWidth = useRecoilComponentValueV2(
|
||||||
|
dropdownMaxWidthComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setDropdownPlacement(dropdownPlacement);
|
||||||
|
}, [dropdownPlacement, setDropdownPlacement]);
|
||||||
|
|
||||||
|
useListenClickOutside({
|
||||||
|
refs: [floatingUiRefs.floating, floatingUiRefs.domReference],
|
||||||
|
listenerId: dropdownId,
|
||||||
|
callback: (event) => {
|
||||||
|
if (activeDropdownFocusId !== dropdownId) return;
|
||||||
|
|
||||||
|
if (isDropdownOpen) {
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
closeDropdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickOutside?.();
|
||||||
|
},
|
||||||
|
excludedClickOutsideIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
useInternalHotkeyScopeManagement({
|
||||||
|
dropdownScopeId: dropdownId,
|
||||||
|
dropdownHotkeyScopeFromParent: hotkeyScope,
|
||||||
|
});
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Escape],
|
||||||
|
() => {
|
||||||
|
if (activeDropdownFocusId !== dropdownId) return;
|
||||||
|
|
||||||
|
if (isDropdownOpen) {
|
||||||
|
closeDropdown();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hotkeyScope?.scope,
|
||||||
|
[closeDropdown, isDropdownOpen],
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownMenuStyles = {
|
||||||
|
...floatingStyles,
|
||||||
|
maxHeight: dropdownMaxHeight,
|
||||||
|
maxWidth: dropdownMaxWidth,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { excludedClickOutsideId } = useContext(ClickOutsideListenerContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{hotkey && onHotkeyTriggered && (
|
||||||
|
<HotkeyEffect hotkey={hotkey} onHotkeyTriggered={onHotkeyTriggered} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<FloatingPortal>
|
||||||
|
<StyledDropdownContentContainer
|
||||||
|
ref={floatingUiRefs.setFloating}
|
||||||
|
style={dropdownMenuStyles}
|
||||||
|
role="listbox"
|
||||||
|
id={`${dropdownId}-options`}
|
||||||
|
data-click-outside-id={excludedClickOutsideId}
|
||||||
|
>
|
||||||
|
<OverlayContainer>
|
||||||
|
<StyledDropdownInsideContainer id={dropdownId} data-select-disable>
|
||||||
|
{dropdownComponents}
|
||||||
|
</StyledDropdownInsideContainer>
|
||||||
|
</OverlayContainer>
|
||||||
|
</StyledDropdownContentContainer>
|
||||||
|
</FloatingPortal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export enum GenericDropdownContentWidth {
|
||||||
|
Narrow = 160,
|
||||||
|
Medium = 200,
|
||||||
|
Large = 240,
|
||||||
|
ExtraLarge = 320,
|
||||||
|
}
|
||||||
@ -1,12 +1,11 @@
|
|||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
|
import { StyledDropdownContentContainer } from '@/ui/layout/dropdown/components/internal/DropdownInternalContainer';
|
||||||
|
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
||||||
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { FloatingPortal, offset, shift, useFloating } from '@floating-ui/react';
|
import { FloatingPortal, offset, shift, useFloating } from '@floating-ui/react';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { StyledDropdownContentContainer } from '@/ui/layout/dropdown/components/DropdownContent';
|
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
|
||||||
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
|
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
|
||||||
|
|
||||||
type ExpandedListDropdownProps = {
|
type ExpandedListDropdownProps = {
|
||||||
anchorElement?: HTMLElement;
|
anchorElement?: HTMLElement;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -40,6 +39,10 @@ export const ExpandedListDropdown = ({
|
|||||||
listenerId: 'expandable-list',
|
listenerId: 'expandable-list',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const dropdownContentWidth = anchorElement
|
||||||
|
? Math.max(220, anchorElement.getBoundingClientRect().width)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FloatingPortal>
|
<FloatingPortal>
|
||||||
<StyledDropdownContentContainer
|
<StyledDropdownContentContainer
|
||||||
@ -47,17 +50,11 @@ export const ExpandedListDropdown = ({
|
|||||||
style={floatingStyles}
|
style={floatingStyles}
|
||||||
>
|
>
|
||||||
<OverlayContainer>
|
<OverlayContainer>
|
||||||
<DropdownMenu
|
<DropdownContent widthInPixels={dropdownContentWidth}>
|
||||||
width={
|
|
||||||
anchorElement
|
|
||||||
? Math.max(220, anchorElement.getBoundingClientRect().width)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<StyledExpandedListContainer>
|
<StyledExpandedListContainer>
|
||||||
{children}
|
{children}
|
||||||
</StyledExpandedListContainer>
|
</StyledExpandedListContainer>
|
||||||
</DropdownMenu>
|
</DropdownContent>
|
||||||
</OverlayContainer>
|
</OverlayContainer>
|
||||||
</StyledDropdownContentContainer>
|
</StyledDropdownContentContainer>
|
||||||
</FloatingPortal>
|
</FloatingPortal>
|
||||||
|
|||||||
@ -9,7 +9,6 @@ export const OverlayContainer = styled.div<{
|
|||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
backdrop-filter: ${({ theme }) => theme.blur.medium};
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
border-radius: ${({ theme, borderRadius }) =>
|
border-radius: ${({ theme, borderRadius }) =>
|
||||||
theme.border.radius[borderRadius ?? 'md']};
|
theme.border.radius[borderRadius ?? 'md']};
|
||||||
|
|||||||
@ -1,101 +0,0 @@
|
|||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
|
||||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
|
||||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|
||||||
import { SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID } from '@/ui/layout/show-page/constants/ShowPageAddButtonDropdownId';
|
|
||||||
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
|
||||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
|
||||||
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
|
||||||
import { Dropdown } from '../../dropdown/components/Dropdown';
|
|
||||||
import { Button } from 'twenty-ui/input';
|
|
||||||
import { IconCheckbox, IconNotes, IconPlus } from 'twenty-ui/display';
|
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
z-index: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const ShowPageAddButton = ({
|
|
||||||
activityTargetObject,
|
|
||||||
}: {
|
|
||||||
activityTargetObject: ActivityTargetableObject;
|
|
||||||
}) => {
|
|
||||||
const { closeDropdown } = useDropdown(SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID);
|
|
||||||
|
|
||||||
const openNote = useOpenCreateActivityDrawer({
|
|
||||||
activityObjectNameSingular: CoreObjectNameSingular.Note,
|
|
||||||
});
|
|
||||||
const openTask = useOpenCreateActivityDrawer({
|
|
||||||
activityObjectNameSingular: CoreObjectNameSingular.Task,
|
|
||||||
});
|
|
||||||
|
|
||||||
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
|
|
||||||
|
|
||||||
const handleSelect = (objectNameSingular: CoreObjectNameSingular) => {
|
|
||||||
if (objectNameSingular === CoreObjectNameSingular.Note) {
|
|
||||||
openNote({
|
|
||||||
targetableObjects: [activityTargetObject],
|
|
||||||
});
|
|
||||||
} else if (objectNameSingular === CoreObjectNameSingular.Task) {
|
|
||||||
openTask({
|
|
||||||
targetableObjects: [activityTargetObject],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
closeDropdown();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
activityTargetObject.targetObjectNameSingular ===
|
|
||||||
CoreObjectNameSingular.Task ||
|
|
||||||
activityTargetObject.targetObjectNameSingular ===
|
|
||||||
CoreObjectNameSingular.Note ||
|
|
||||||
isWorkflowSubObjectMetadata(activityTargetObject.targetObjectNameSingular)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasObjectReadOnlyPermission) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer>
|
|
||||||
<Dropdown
|
|
||||||
dropdownId={SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID}
|
|
||||||
clickableComponent={
|
|
||||||
<Button
|
|
||||||
Icon={IconPlus}
|
|
||||||
dataTestId="add-button"
|
|
||||||
size="small"
|
|
||||||
variant="secondary"
|
|
||||||
accent="default"
|
|
||||||
title="New note/task"
|
|
||||||
ariaLabel="New note/task"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
dropdownComponents={
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => handleSelect(CoreObjectNameSingular.Note)}
|
|
||||||
accent="default"
|
|
||||||
LeftIcon={IconNotes}
|
|
||||||
text="Note"
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => handleSelect(CoreObjectNameSingular.Task)}
|
|
||||||
accent="default"
|
|
||||||
LeftIcon={IconCheckbox}
|
|
||||||
text="Task"
|
|
||||||
/>
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
}
|
|
||||||
dropdownHotkeyScope={{ scope: PageHotkeyScope.ShowPage }}
|
|
||||||
/>
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -11,6 +11,7 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac
|
|||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -92,7 +93,7 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -116,20 +117,21 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
|||||||
dropdownId={'multi-workspace-dropdown-context-menu'}
|
dropdownId={'multi-workspace-dropdown-context-menu'}
|
||||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownContent>
|
||||||
<MenuItem
|
<DropdownMenuItemsContainer>
|
||||||
LeftIcon={IconPlus}
|
<MenuItem
|
||||||
text={t`Create Workspace`}
|
LeftIcon={IconPlus}
|
||||||
onClick={createWorkspace}
|
text={t`Create Workspace`}
|
||||||
/>
|
onClick={createWorkspace}
|
||||||
</DropdownMenuItemsContainer>
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{currentWorkspace?.displayName}
|
{currentWorkspace?.displayName}
|
||||||
</DropdownMenuHeader>
|
</DropdownMenuHeader>
|
||||||
<DropdownMenuSeparator />
|
|
||||||
{workspaces.length > 1 && (
|
{workspaces.length > 1 && (
|
||||||
<>
|
<>
|
||||||
<StyledDropdownMenuItemsContainer>
|
<StyledDropdownMenuItemsContainer>
|
||||||
@ -193,6 +195,6 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
|||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
<MenuItem LeftIcon={IconLogout} text={t`Log out`} onClick={signOut} />
|
<MenuItem LeftIcon={IconLogout} text={t`Log out`} onClick={signOut} />
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -7,7 +8,6 @@ import { useLingui } from '@lingui/react/macro';
|
|||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { IconCheck, IconChevronLeft } from 'twenty-ui/display';
|
import { IconCheck, IconChevronLeft } from 'twenty-ui/display';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
|
||||||
|
|
||||||
export const MultiWorkspaceDropdownThemesComponents = () => {
|
export const MultiWorkspaceDropdownThemesComponents = () => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
@ -19,7 +19,7 @@ export const MultiWorkspaceDropdownThemesComponents = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -30,7 +30,6 @@ export const MultiWorkspaceDropdownThemesComponents = () => {
|
|||||||
>
|
>
|
||||||
{t`Theme`}
|
{t`Theme`}
|
||||||
</DropdownMenuHeader>
|
</DropdownMenuHeader>
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{colorSchemeList.map((theme) => (
|
{colorSchemeList.map((theme) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@ -43,6 +42,6 @@ export const MultiWorkspaceDropdownThemesComponents = () => {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|||||||
import { Workspaces, workspacesState } from '@/auth/states/workspaces';
|
import { Workspaces, workspacesState } from '@/auth/states/workspaces';
|
||||||
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
|
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
|
||||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||||
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@ -32,7 +33,7 @@ export const MultiWorkspaceDropdownWorkspacesListComponents = () => {
|
|||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DropdownContent>
|
||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
StartComponent={
|
StartComponent={
|
||||||
<DropdownMenuHeaderLeftComponent
|
<DropdownMenuHeaderLeftComponent
|
||||||
@ -43,7 +44,6 @@ export const MultiWorkspaceDropdownWorkspacesListComponents = () => {
|
|||||||
>
|
>
|
||||||
{t`Other workspaces`}
|
{t`Other workspaces`}
|
||||||
</DropdownMenuHeader>
|
</DropdownMenuHeader>
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<DropdownMenuSearchInput
|
<DropdownMenuSearchInput
|
||||||
placeholder={t`Search`}
|
placeholder={t`Search`}
|
||||||
autoFocus
|
autoFocus
|
||||||
@ -83,6 +83,6 @@ export const MultiWorkspaceDropdownWorkspacesListComponents = () => {
|
|||||||
</UndecoratedLink>
|
</UndecoratedLink>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user