Skip to content
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
984bf6e
feat: integrate EditActionsButton into RecordIndex and RecordShow com…
ehconitin Mar 18, 2026
a7bb9b0
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 18, 2026
9a9cc0c
feat: enhance command menus with feature flag support and new components
ehconitin Mar 18, 2026
047e2ae
feat: integrate feature flag for command menu items in metadata loading
ehconitin Mar 18, 2026
e08c292
refactor: update side panel navigation to use CommandMenuDisplay and …
ehconitin Mar 18, 2026
e722f5c
chore: code path seperatiopn
ehconitin Mar 18, 2026
539f182
refactor: new pin icon
ehconitin Mar 18, 2026
320c84c
refactor: consolidate all flag-ON command menu code under server-items/
ehconitin Mar 18, 2026
74ca958
refactor: remove standard command menu item defaults constants
ehconitin Mar 18, 2026
2e5bdab
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 19, 2026
b3a532e
refactor: remove unused state in SidePanelCommandMenuItemEditPage
ehconitin Mar 19, 2026
f692427
feat: enhance EditActionsButton with copy context functionality and u…
ehconitin Mar 19, 2026
c0e5923
chore: rename
ehconitin Mar 19, 2026
f372306
chore: lint
ehconitin Mar 19, 2026
3588f7c
refactor: remove isAllowedDuringGlobalLayoutCustomization from comman…
ehconitin Mar 19, 2026
239cb7f
review
ehconitin Mar 19, 2026
bd8c9dc
refactor: remove id prop from CommandMenuItemDraggable and update ref…
ehconitin Mar 19, 2026
2d30f24
refactor: /display folder
ehconitin Mar 19, 2026
6c46478
feat: enhance CommandMenuEditRecordSelectionDropdown with single and …
ehconitin Mar 19, 2026
eb937a9
feat: update CommandMenuContextProviderServerItems and related compon…
ehconitin Mar 19, 2026
f95f1a9
feat: refactor command menu components
ehconitin Mar 19, 2026
3b77d8e
refactor: lint + shuffle
ehconitin Mar 19, 2026
3c205de
cleanup
ehconitin Mar 19, 2026
393bf2b
feat: add data attribute for click outside functionality in SidePanel…
ehconitin Mar 20, 2026
7c90b2c
refactor: unify command menu context handling and improve item select…
ehconitin Mar 20, 2026
442c28d
refactor: streamline command menu context API and enhance record sele…
ehconitin Mar 20, 2026
b1ea211
refactor: update CommandMenuItemOptionsDropdown to use CommandMenuIte…
ehconitin Mar 20, 2026
550b51e
refactor: improve position calculation for reordering command menu it…
ehconitin Mar 20, 2026
bf5b034
refactor: normalize short label handling in CommandMenuItemOptionsDro…
ehconitin Mar 20, 2026
42cb345
chore: lint
ehconitin Mar 20, 2026
9d88056
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 20, 2026
f09ef69
refactor: streamline command menu context API and display overflow
ehconitin Mar 20, 2026
6e36176
chore: lint
ehconitin Mar 20, 2026
c54e981
refactor: optimize search functionality in SidePanelCommandMenuItemEd…
ehconitin Mar 20, 2026
2c121b9
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 20, 2026
7a9ab4f
revert: revert seed
ehconitin Mar 20, 2026
705b637
Merge remote-tracking branch 'origin/main' into command-menu-item-edi…
charlesBochet Mar 22, 2026
a8e68c0
revert: bad conflict resolution
ehconitin Mar 23, 2026
f2a4352
refactor: address PR review feedback batch 1
ehconitin Mar 23, 2026
e90865d
refactor: address PR review feedback batch 2
ehconitin Mar 23, 2026
7ab77f0
refactor: split context API into composable hooks and separate displa…
ehconitin Mar 23, 2026
d0ed3b7
refactor(twenty-front): centralize command-menu context instance wiring
ehconitin Mar 23, 2026
35e4109
refactor: simplify conditional rendering in SidePanelCommandMenu comp…
ehconitin Mar 23, 2026
2181df3
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 23, 2026
0d30f1e
lint
ehconitin Mar 23, 2026
cab2fd0
feat(command-menu): add overrides default-values flow and resolved me…
ehconitin Mar 23, 2026
6dc63a7
chore: regenerate the migration file and some fixes
ehconitin Mar 23, 2026
b34acd7
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 23, 2026
d35e071
fix: typecheck
ehconitin Mar 23, 2026
b8cd83c
chore: lint
ehconitin Mar 23, 2026
429307a
twenty-sdk: generate metadata
ehconitin Mar 23, 2026
62888ed
chore: lint
ehconitin Mar 23, 2026
839ad0f
Merge remote-tracking branch 'upstream/main' into command-menu-item-e…
ehconitin Mar 23, 2026
89a2b16
Merge upstream/main into command-menu-item-edition
ehconitin Mar 24, 2026
850354f
review: refactor + new provider
ehconitin Mar 24, 2026
c3d4708
fix
ehconitin Mar 24, 2026
4ea0b94
cleanup: unused file + fix
ehconitin Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { styled } from '@linaria/react';
import { motion } from 'framer-motion';
import { useContext } from 'react';
import { type IconComponent } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';

type AnimatedIconCrossfadeProps = {
isToggled: boolean;
DefaultIcon: IconComponent;
ToggledIcon: IconComponent;
};

const StyledContainer = styled.div`
height: calc(${themeCssVariables.icon.size.sm} * 1px);
overflow: hidden;
position: relative;
width: calc(${themeCssVariables.icon.size.sm} * 1px);
`;

const StyledLayer = styled(motion.div)`
align-items: center;
display: flex;
inset: 0;
justify-content: center;
position: absolute;
`;

export const AnimatedIconCrossfade = ({
isToggled,
DefaultIcon,
ToggledIcon,
}: AnimatedIconCrossfadeProps) => {
const { theme } = useContext(ThemeContext);

return (
<StyledContainer>
<StyledLayer
initial={false}
animate={{
opacity: isToggled ? 0 : 1,
scale: isToggled ? 0.85 : 1,
}}
transition={{
duration: theme.animation.duration.fast,
ease: 'easeInOut',
}}
>
<DefaultIcon size={theme.icon.size.sm} />
</StyledLayer>
<StyledLayer
initial={false}
animate={{
opacity: isToggled ? 1 : 0,
scale: isToggled ? 1 : 0.85,
}}
transition={{
duration: theme.animation.duration.fast,
ease: 'easeInOut',
}}
>
<ToggledIcon size={theme.icon.size.sm} />
</StyledLayer>
</StyledContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { PageHeaderCommandMenuButtons } from '@/command-menu-item/components/PageHeaderCommandMenuButtons';
import { PinnedCommandMenuItemButtons } from '@/command-menu-item/server-items/display/components/PinnedCommandMenuItemButtons';
import { RecordIndexCommandMenuDropdown } from '@/command-menu-item/components/RecordIndexCommandMenuDropdown';
import { CommandMenuContextProvider } from '@/command-menu-item/contexts/CommandMenuContextProvider';
import { CommandMenuItemEditButton } from '@/command-menu-item/server-items/edit/components/CommandMenuItemEditButton';
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { useIsMobile } from 'twenty-ui/utilities';

export const RecordIndexCommandMenu = () => {
Expand All @@ -13,6 +17,9 @@ export const RecordIndexCommandMenu = () => {
);

const isMobile = useIsMobile();
const isCommandMenuItemEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
);

return (
<>
Expand All @@ -23,7 +30,12 @@ export const RecordIndexCommandMenu = () => {
displayType="button"
containerType="index-page-header"
>
{!isMobile && <PageHeaderCommandMenuButtons />}
{!isMobile &&
(isCommandMenuItemEnabled ? (
<PinnedCommandMenuItemButtons />
) : (
<PageHeaderCommandMenuButtons />
))}
</CommandMenuContextProvider>
<CommandMenuContextProvider
isInSidePanel={false}
Expand All @@ -32,6 +44,7 @@ export const RecordIndexCommandMenu = () => {
>
<RecordIndexCommandMenuDropdown />
</CommandMenuContextProvider>
<CommandMenuItemEditButton />
</>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { PageHeaderCommandMenuButtons } from '@/command-menu-item/components/PageHeaderCommandMenuButtons';
import { PinnedCommandMenuItemButtons } from '@/command-menu-item/server-items/display/components/PinnedCommandMenuItemButtons';
import { CommandMenuContextProvider } from '@/command-menu-item/contexts/CommandMenuContextProvider';
import { CommandMenuItemEditButton } from '@/command-menu-item/server-items/edit/components/CommandMenuItemEditButton';
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { useIsMobile } from 'twenty-ui/utilities';

export const RecordShowCommandMenu = () => {
Expand All @@ -22,17 +26,28 @@ export const RecordShowCommandMenu = () => {
contextStoreTargetedRecordsRule.selectedRecordIds.length === 1;

const isMobile = useIsMobile();
const isCommandMenuItemEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
);

return (
<>
{hasSelectedRecord && contextStoreCurrentObjectMetadataItemId && (
<CommandMenuContextProvider
isInSidePanel={false}
displayType="button"
containerType="show-page-header"
>
{!isMobile && <PageHeaderCommandMenuButtons />}
</CommandMenuContextProvider>
<>
<CommandMenuContextProvider
isInSidePanel={false}
displayType="button"
containerType="show-page-header"
>
{!isMobile &&
(isCommandMenuItemEnabled ? (
<PinnedCommandMenuItemButtons />
) : (
<PageHeaderCommandMenuButtons />
))}
</CommandMenuContextProvider>
<CommandMenuItemEditButton />
</>
)}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ export type CommandMenuContextType = {
isInSidePanel: boolean;
displayType: 'button' | 'listItem' | 'dropdownItem';
containerType: CommandMenuItemContainerType;
contextStoreInstanceId?: string;
commandMenuItems: CommandMenuItemConfig[];
};

export const CommandMenuContext = createContext<CommandMenuContextType>({
isInSidePanel: false,
containerType: 'command-menu-list',
displayType: 'button',
contextStoreInstanceId: undefined,
commandMenuItems: [],
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext';
import { CommandMenuContextProviderLegacy } from '@/command-menu-item/contexts/CommandMenuContextProviderLegacy';
import { CommandMenuContextProviderServerItems } from '@/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems';
import { CommandMenuContextProviderServerItems } from '@/command-menu-item/server-items/common/contexts/CommandMenuContextProviderServerItems';
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
Expand All @@ -11,9 +11,11 @@ export const CommandMenuContextProvider = ({
displayType,
containerType,
objectMetadataItemOverride,
contextStoreInstanceId,
}: Omit<CommandMenuContextType, 'commandMenuItems'> & {
children: React.ReactNode;
objectMetadataItemOverride?: EnrichedObjectMetadataItem;
contextStoreInstanceId?: string;
}) => {
const isCommandMenuItemEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
Expand All @@ -25,6 +27,7 @@ export const CommandMenuContextProvider = ({
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
contextStoreInstanceId={contextStoreInstanceId}
>
{children}
</CommandMenuContextProviderServerItems>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ export const CommandMenuContextProviderDefault = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
children,
}: {
objectMetadataItem: EnrichedObjectMetadataItem;
isInSidePanel: CommandMenuContextType['isInSidePanel'];
displayType: CommandMenuContextType['displayType'];
containerType: CommandMenuContextType['containerType'];
contextStoreInstanceId?: CommandMenuContextType['contextStoreInstanceId'];
children: React.ReactNode;
}) => {
const shouldBeRegisteredParams = useShouldCommandMenuItemBeRegisteredParams({
Expand Down Expand Up @@ -53,6 +55,7 @@ export const CommandMenuContextProviderDefault = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordCommands,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const CommandMenuContextProviderLegacy = ({
displayType,
containerType,
objectMetadataItemOverride,
contextStoreInstanceId,
}: Omit<CommandMenuContextType, 'commandMenuItems'> & {
children: React.ReactNode;
objectMetadataItemOverride?: EnrichedObjectMetadataItem;
Expand Down Expand Up @@ -45,6 +46,7 @@ export const CommandMenuContextProviderLegacy = ({
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
contextStoreInstanceId={contextStoreInstanceId}
objectMetadataItem={objectMetadataItem}
>
{children}
Expand All @@ -57,6 +59,7 @@ export const CommandMenuContextProviderLegacy = ({
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
contextStoreInstanceId={contextStoreInstanceId}
objectMetadataItem={objectMetadataItem}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type CommandMenuContextProviderWorkflowObjectsProps = {
isInSidePanel: CommandMenuContextType['isInSidePanel'];
displayType: CommandMenuContextType['displayType'];
containerType: CommandMenuContextType['containerType'];
contextStoreInstanceId?: CommandMenuContextType['contextStoreInstanceId'];
children: React.ReactNode;
};

Expand All @@ -27,6 +28,7 @@ const CommandMenuContextProviderWorkflowObjectsContent = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
children,
selectedRecordId,
}: CommandMenuContextProviderWorkflowObjectsProps & {
Expand Down Expand Up @@ -57,6 +59,7 @@ const CommandMenuContextProviderWorkflowObjectsContent = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordAgnosticCommands,
Expand All @@ -73,6 +76,7 @@ const CommandMenuContextProviderWorkflowObjectsWithoutWorkflow = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
children,
}: CommandMenuContextProviderWorkflowObjectsProps & {
workflowWithCurrentVersion: WorkflowWithCurrentVersion | undefined;
Expand All @@ -99,6 +103,7 @@ const CommandMenuContextProviderWorkflowObjectsWithoutWorkflow = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
commandMenuItems: [
...commandMenuItems,
...runWorkflowRecordAgnosticCommands,
Expand All @@ -115,6 +120,7 @@ export const CommandMenuContextProviderWorkflowObjects = ({
isInSidePanel,
displayType,
containerType,
contextStoreInstanceId,
children,
}: CommandMenuContextProviderWorkflowObjectsProps) => {
const contextStoreTargetedRecordsRule = useAtomComponentStateValue(
Expand All @@ -138,6 +144,7 @@ export const CommandMenuContextProviderWorkflowObjects = ({
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
contextStoreInstanceId={contextStoreInstanceId}
selectedRecordId={selectedRecord.id}
>
{children}
Expand All @@ -151,6 +158,7 @@ export const CommandMenuContextProviderWorkflowObjects = ({
isInSidePanel={isInSidePanel}
displayType={displayType}
containerType={containerType}
contextStoreInstanceId={contextStoreInstanceId}
workflowWithCurrentVersion={undefined}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
import { useContext } from 'react';

export const useCommandMenuContextStoreInstanceId = () =>
useContext(CommandMenuContext).contextStoreInstanceId;
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { CommandMenuContextProvider } from '@/command-menu-item/contexts/CommandMenuContextProvider';
import { SidePanelCommandMenuItemEditPage } from '@/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage';
import { SidePanelCommandMenuItemDisplayPage } from '@/command-menu-item/server-items/display/components/SidePanelCommandMenuItemDisplayPage';
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
import { SidePanelRootPage } from '@/side-panel/pages/root/components/SidePanelRootPage';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';

const SidePanelCommandMenuPageWithMainContext = ({
children,
}: {
children: React.ReactNode;
}) => (
<CommandMenuContextProvider
isInSidePanel={true}
displayType="listItem"
containerType="command-menu-list"
contextStoreInstanceId={MAIN_CONTEXT_STORE_INSTANCE_ID}
>
{children}
</CommandMenuContextProvider>
);

export const SidePanelCommandMenuDisplayPageEntry = () => {
const isCommandMenuItemEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
);

if (!isCommandMenuItemEnabled) {
return <SidePanelRootPage />;
}

return (
<SidePanelCommandMenuPageWithMainContext>
<SidePanelCommandMenuItemDisplayPage />
</SidePanelCommandMenuPageWithMainContext>
);
};

export const SidePanelCommandMenuEditPageEntry = () => {
const isCommandMenuItemEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
);

if (!isCommandMenuItemEnabled) {
return <SidePanelRootPage />;
}

return (
<SidePanelCommandMenuPageWithMainContext>
<SidePanelCommandMenuItemEditPage />
</SidePanelCommandMenuPageWithMainContext>
);
};
Loading
Loading