diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx
index 208ae8ffc..d53e118ae 100644
--- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx
+++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx
@@ -102,6 +102,7 @@ export const DeleteRecordsActionEffect = ({
position,
Icon: IconTrash,
accent: 'danger',
+ isPinned: true,
onClick: () => {
setIsDeleteRecordsModalOpen(true);
},
diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx
index ea0383727..9a22c29f9 100644
--- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx
+++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx
@@ -1,5 +1,6 @@
import styled from '@emotion/styled';
+import { RecordIndexActionMenuBarAllActionsButton } from '@/action-menu/components/RecordIndexActionMenuBarAllActionsButton';
import { RecordIndexActionMenuBarEntry } from '@/action-menu/components/RecordIndexActionMenuBarEntry';
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
@@ -30,7 +31,9 @@ export const RecordIndexActionMenuBar = () => {
actionMenuEntriesComponentSelector,
);
- if (actionMenuEntries.length === 0) {
+ const pinnedEntries = actionMenuEntries.filter((entry) => entry.isPinned);
+
+ if (pinnedEntries.length === 0) {
return null;
}
@@ -42,9 +45,10 @@ export const RecordIndexActionMenuBar = () => {
}}
>
{contextStoreNumberOfSelectedRecords} selected:
- {actionMenuEntries.map((entry, index) => (
+ {pinnedEntries.map((entry, index) => (
))}
+
);
};
diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx
new file mode 100644
index 000000000..336b4f734
--- /dev/null
+++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx
@@ -0,0 +1,53 @@
+import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
+import { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import { IconLayoutSidebarRightExpand } from 'twenty-ui';
+
+const StyledButton = styled.div`
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+
+ padding: ${({ theme }) => theme.spacing(2)};
+ transition: background ${({ theme }) => theme.animation.duration.fast} ease;
+ user-select: none;
+
+ &:hover {
+ background: ${({ theme }) => theme.background.tertiary};
+ }
+`;
+
+const StyledButtonLabel = styled.div`
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ margin-left: ${({ theme }) => theme.spacing(1)};
+`;
+
+const StyledShortcutLabel = styled.div`
+ color: ${({ theme }) => theme.font.color.light};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+`;
+
+const StyledSeparator = styled.div<{ size: 'sm' | 'md' }>`
+ background: ${({ theme }) => theme.border.color.light};
+ height: ${({ theme, size }) => theme.spacing(size === 'sm' ? 4 : 8)};
+ margin: 0 ${({ theme }) => theme.spacing(1)};
+ width: 1px;
+`;
+
+export const RecordIndexActionMenuBarAllActionsButton = () => {
+ const theme = useTheme();
+ const { openCommandMenu } = useCommandMenu();
+ return (
+ <>
+
+ openCommandMenu()}>
+
+ All Actions
+
+ ⌘K
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx
index 8be474798..ffa52d205 100644
--- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx
+++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx
@@ -2,31 +2,24 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
-import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent';
type RecordIndexActionMenuBarEntryProps = {
entry: ActionMenuEntry;
};
-const StyledButton = styled.div<{ accent: MenuItemAccent }>`
+const StyledButton = styled.div`
border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${(props) =>
- props.accent === 'danger'
- ? props.theme.color.red
- : props.theme.font.color.secondary};
+ color: ${({ theme }) => theme.font.color.secondary};
cursor: pointer;
display: flex;
justify-content: center;
padding: ${({ theme }) => theme.spacing(2)};
- transition: background 0.1s ease;
+ transition: background ${({ theme }) => theme.animation.duration.fast} ease;
user-select: none;
&:hover {
- background: ${({ theme, accent }) =>
- accent === 'danger'
- ? theme.background.danger
- : theme.background.tertiary};
+ background: ${({ theme }) => theme.background.tertiary};
}
`;
@@ -40,10 +33,7 @@ export const RecordIndexActionMenuBarEntry = ({
}: RecordIndexActionMenuBarEntryProps) => {
const theme = useTheme();
return (
- entry.onClick?.()}
- >
+ entry.onClick?.()}>
{entry.Icon && }
{entry.label}
diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx
index f3a3eab2f..4cb1ef1a4 100644
--- a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx
+++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx
@@ -10,15 +10,15 @@ import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-sto
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState';
import { userEvent, waitFor, within } from '@storybook/test';
-import { IconCheckbox, IconTrash } from 'twenty-ui';
+import { IconTrash, RouterDecorator } from 'twenty-ui';
const deleteMock = jest.fn();
-const markAsDoneMock = jest.fn();
const meta: Meta = {
title: 'Modules/ActionMenu/RecordIndexActionMenuBar',
component: RecordIndexActionMenuBar,
decorators: [
+ RouterDecorator,
(Story) => (
= {
[
'delete',
{
+ isPinned: true,
key: 'delete',
label: 'Delete',
position: 0,
@@ -55,16 +56,6 @@ const meta: Meta = {
onClick: deleteMock,
},
],
- [
- 'markAsDone',
- {
- key: 'markAsDone',
- label: 'Mark as done',
- position: 1,
- Icon: IconCheckbox,
- onClick: markAsDoneMock,
- },
- ],
]),
);
set(
@@ -120,12 +111,8 @@ export const WithButtonClicks: Story = {
const deleteButton = await canvas.findByText('Delete');
await userEvent.click(deleteButton);
- const markAsDoneButton = await canvas.findByText('Mark as done');
- await userEvent.click(markAsDoneButton);
-
await waitFor(() => {
expect(deleteMock).toHaveBeenCalled();
- expect(markAsDoneMock).toHaveBeenCalled();
});
},
};
diff --git a/packages/twenty-front/src/modules/action-menu/types/ActionMenuEntry.ts b/packages/twenty-front/src/modules/action-menu/types/ActionMenuEntry.ts
index 4fe180955..c6f559be8 100644
--- a/packages/twenty-front/src/modules/action-menu/types/ActionMenuEntry.ts
+++ b/packages/twenty-front/src/modules/action-menu/types/ActionMenuEntry.ts
@@ -8,6 +8,7 @@ export type ActionMenuEntry = {
label: string;
position: number;
Icon: IconComponent;
+ isPinned?: boolean;
accent?: MenuItemAccent;
onClick?: (event?: MouseEvent) => void;
ConfirmationModal?: ReactNode;