Skip to content

Commit afeef8e

Browse files

File tree

74 files changed

+2516
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+2516
-237
lines changed

packages/twenty-front/jest.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const jestConfig = {
6161
extensionsToTreatAsEsm: ['.ts', '.tsx'],
6262
coverageThreshold: {
6363
global: {
64-
statements: 48.5,
64+
statements: 48.4,
6565
lines: 47.0,
6666
functions: 39.5,
6767
},

packages/twenty-front/src/modules/command-menu-item/components/RecordIndexCommandMenu.tsx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import { PageHeaderCommandMenuButtons } from '@/command-menu-item/components/PageHeaderCommandMenuButtons';
2+
import { PinnedCommandMenuItemButtons } from '@/command-menu-item/server-items/display/components/PinnedCommandMenuItemButtons';
23
import { RecordIndexCommandMenuDropdown } from '@/command-menu-item/components/RecordIndexCommandMenuDropdown';
34
import { CommandMenuContextProvider } from '@/command-menu-item/contexts/CommandMenuContextProvider';
5+
import { CommandMenuItemEditButton } from '@/command-menu-item/server-items/edit/components/CommandMenuItemEditButton';
6+
import { PinnedCommandMenuItemButtonsEditMode } from '@/command-menu-item/server-items/edit/components/PinnedCommandMenuItemButtonsEditMode';
47
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
58
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
9+
import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState';
610
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
11+
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
12+
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
13+
import { FeatureFlagKey } from '~/generated-metadata/graphql';
714
import { useIsMobile } from 'twenty-ui/utilities';
815

916
export const RecordIndexCommandMenu = () => {
@@ -13,25 +20,44 @@ export const RecordIndexCommandMenu = () => {
1320
);
1421

1522
const isMobile = useIsMobile();
23+
const isCommandMenuItemEnabled = useIsFeatureEnabled(
24+
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
25+
);
26+
const isLayoutCustomizationModeEnabled = useAtomStateValue(
27+
isLayoutCustomizationModeEnabledState,
28+
);
29+
30+
const showEditModePinnedButtons =
31+
isCommandMenuItemEnabled && isLayoutCustomizationModeEnabled;
1632

1733
return (
1834
<>
1935
{contextStoreCurrentObjectMetadataItemId && (
2036
<>
21-
<CommandMenuContextProvider
22-
isInSidePanel={false}
23-
displayType="button"
24-
containerType="index-page-header"
25-
>
26-
{!isMobile && <PageHeaderCommandMenuButtons />}
27-
</CommandMenuContextProvider>
37+
{!isMobile && showEditModePinnedButtons ? (
38+
<PinnedCommandMenuItemButtonsEditMode />
39+
) : (
40+
<CommandMenuContextProvider
41+
isInSidePanel={false}
42+
displayType="button"
43+
containerType="index-page-header"
44+
>
45+
{!isMobile &&
46+
(isCommandMenuItemEnabled ? (
47+
<PinnedCommandMenuItemButtons />
48+
) : (
49+
<PageHeaderCommandMenuButtons />
50+
))}
51+
</CommandMenuContextProvider>
52+
)}
2853
<CommandMenuContextProvider
2954
isInSidePanel={false}
3055
displayType="dropdownItem"
3156
containerType="index-page-dropdown"
3257
>
3358
<RecordIndexCommandMenuDropdown />
3459
</CommandMenuContextProvider>
60+
<CommandMenuItemEditButton />
3561
</>
3662
)}
3763
</>

packages/twenty-front/src/modules/command-menu-item/components/RecordShowCommandMenu.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { PageHeaderCommandMenuButtons } from '@/command-menu-item/components/PageHeaderCommandMenuButtons';
2+
import { PinnedCommandMenuItemButtons } from '@/command-menu-item/server-items/display/components/PinnedCommandMenuItemButtons';
23
import { CommandMenuContextProvider } from '@/command-menu-item/contexts/CommandMenuContextProvider';
4+
import { CommandMenuItemEditButton } from '@/command-menu-item/server-items/edit/components/CommandMenuItemEditButton';
35
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
46
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
57
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
68
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
9+
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
10+
import { FeatureFlagKey } from '~/generated-metadata/graphql';
711
import { useIsMobile } from 'twenty-ui/utilities';
812

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

2428
const isMobile = useIsMobile();
29+
const isCommandMenuItemEnabled = useIsFeatureEnabled(
30+
FeatureFlagKey.IS_COMMAND_MENU_ITEM_ENABLED,
31+
);
2532

2633
return (
2734
<>
2835
{hasSelectedRecord && contextStoreCurrentObjectMetadataItemId && (
29-
<CommandMenuContextProvider
30-
isInSidePanel={false}
31-
displayType="button"
32-
containerType="show-page-header"
33-
>
34-
{!isMobile && <PageHeaderCommandMenuButtons />}
35-
</CommandMenuContextProvider>
36+
<>
37+
<CommandMenuContextProvider
38+
isInSidePanel={false}
39+
displayType="button"
40+
containerType="show-page-header"
41+
>
42+
{!isMobile &&
43+
(isCommandMenuItemEnabled ? (
44+
<PinnedCommandMenuItemButtons />
45+
) : (
46+
<PageHeaderCommandMenuButtons />
47+
))}
48+
</CommandMenuContextProvider>
49+
<CommandMenuItemEditButton />
50+
</>
3651
)}
3752
</>
3853
);

packages/twenty-front/src/modules/command-menu-item/contexts/CommandMenuContextProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext';
22
import { CommandMenuContextProviderLegacy } from '@/command-menu-item/contexts/CommandMenuContextProviderLegacy';
3-
import { CommandMenuContextProviderServerItems } from '@/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems';
3+
import { CommandMenuContextProviderServerItems } from '@/command-menu-item/server-items/common/contexts/CommandMenuContextProviderServerItems';
44
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
55
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
66
import { FeatureFlagKey } from '~/generated-metadata/graphql';

packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItems.tsx renamed to packages/twenty-front/src/modules/command-menu-item/server-items/common/contexts/CommandMenuContextProviderServerItems.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { CoreObjectNameSingular } from 'twenty-shared/types';
22
import { isDefined } from 'twenty-shared/utils';
33

4-
import { useCommandMenuContextApi } from '@/command-menu-item/server-items/hooks/useCommandMenuContextApi';
54
import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext';
5+
import { useCommandMenuContextApi } from '@/command-menu-item/server-items/common/hooks/useCommandMenuContextApi';
66

77
import { CommandMenuContextProviderServerItemsContent } from './CommandMenuContextProviderServerItemsContent';
88
import { CommandMenuContextProviderServerItemsWithWorkflowEnrichment } from './CommandMenuContextProviderServerItemsWithWorkflowEnrichment';

packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsContent.tsx renamed to packages/twenty-front/src/modules/command-menu-item/server-items/common/contexts/CommandMenuContextProviderServerItemsContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
CommandMenuContext,
33
type CommandMenuContextType,
44
} from '@/command-menu-item/contexts/CommandMenuContext';
5-
import { useCommandMenuItemsFromBackend } from '@/command-menu-item/server-items/hooks/useCommandMenuItemsFromBackend';
5+
import { useCommandMenuItemsFromBackend } from '@/command-menu-item/server-items/common/hooks/useCommandMenuItemsFromBackend';
66
import { type CommandMenuContextApi } from 'twenty-shared/types';
77

88
type CommandMenuContextProviderServerItemsContentProps = {

packages/twenty-front/src/modules/command-menu-item/server-items/contexts/CommandMenuContextProviderServerItemsWithWorkflowEnrichment.tsx renamed to packages/twenty-front/src/modules/command-menu-item/server-items/common/contexts/CommandMenuContextProviderServerItemsWithWorkflowEnrichment.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type CommandMenuContextApi } from 'twenty-shared/types';
22
import { isDefined } from 'twenty-shared/utils';
33

44
import { type CommandMenuContextType } from '@/command-menu-item/contexts/CommandMenuContext';
5-
import { useWorkflowsWithCurrentVersions } from '@/command-menu-item/server-items/hooks/useWorkflowsWithCurrentVersions';
5+
import { useWorkflowsWithCurrentVersions } from '@/command-menu-item/server-items/common/hooks/useWorkflowsWithCurrentVersions';
66

77
import { CommandMenuContextProviderServerItemsContent } from './CommandMenuContextProviderServerItemsContent';
88

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { COMMAND_MENU_ITEM_FRAGMENT } from '@/command-menu-item/graphql/fragments/commandMenuItemFragment';
2+
import { gql } from '@apollo/client';
3+
4+
export const UPDATE_COMMAND_MENU_ITEM = gql`
5+
${COMMAND_MENU_ITEM_FRAGMENT}
6+
mutation UpdateCommandMenuItem($input: UpdateCommandMenuItemInput!) {
7+
updateCommandMenuItem(input: $input) {
8+
...CommandMenuItemFields
9+
}
10+
}
11+
`;

packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts renamed to packages/twenty-front/src/modules/command-menu-item/server-items/common/hooks/useCommandMenuContextApi.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
22
import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector';
3-
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
3+
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
44
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
55
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
66
import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState';
@@ -13,13 +13,14 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPe
1313
import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView';
1414
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
1515
import { recordStoreRecordsSelector } from '@/object-record/record-store/states/selectors/recordStoreRecordsSelector';
16+
import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId';
1617
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
1718
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
1819
import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue';
1920
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
21+
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
2022
import { isNonEmptyArray } from '@sniptt/guards';
2123
import { useStore } from 'jotai';
22-
import { useContext } from 'react';
2324
import {
2425
CommandMenuContextApiPageType,
2526
type CommandMenuContextApi,
@@ -29,7 +30,11 @@ import { isDefined } from 'twenty-shared/utils';
2930
export const useCommandMenuContextApi = (): CommandMenuContextApi => {
3031
const store = useStore();
3132

32-
const { isInSidePanel } = useContext(CommandMenuContext);
33+
const contextStoreInstanceId = useAvailableComponentInstanceIdOrThrow(
34+
ContextStoreComponentInstanceContext,
35+
);
36+
const isInSidePanel =
37+
contextStoreInstanceId === SIDE_PANEL_COMPONENT_INSTANCE_ID;
3338

3439
const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue(
3540
contextStoreCurrentObjectMetadataItemIdComponentState,
@@ -39,6 +44,10 @@ export const useCommandMenuContextApi = (): CommandMenuContextApi => {
3944
contextStoreTargetedRecordsRuleComponentState,
4045
);
4146

47+
const contextStoreNumberOfSelectedRecords = useAtomComponentStateValue(
48+
contextStoreNumberOfSelectedRecordsComponentState,
49+
);
50+
4251
const { objectMetadataItems } = useObjectMetadataItems();
4352

4453
const objectMetadataItem = objectMetadataItems.find(
@@ -52,19 +61,16 @@ export const useCommandMenuContextApi = (): CommandMenuContextApi => {
5261
? contextStoreTargetedRecordsRule.selectedRecordIds
5362
: undefined;
5463

55-
const favoriteRecordIds = (() => {
56-
if (!isNonEmptyArray(recordIds) || !isDefined(objectMetadataItem)) {
57-
return [];
58-
}
59-
60-
return recordIds.filter((recordId) =>
61-
navigationMenuItems?.some(
62-
(item) =>
63-
item.targetRecordId === recordId &&
64-
item.targetObjectMetadataId === objectMetadataItem.id,
65-
),
66-
);
67-
})();
64+
const favoriteRecordIds =
65+
!isNonEmptyArray(recordIds) || !isDefined(objectMetadataItem)
66+
? []
67+
: recordIds.filter((recordId) =>
68+
navigationMenuItems?.some(
69+
(item) =>
70+
item.targetRecordId === recordId &&
71+
item.targetObjectMetadataId === objectMetadataItem.id,
72+
),
73+
);
6874

6975
const selectedRecords = useAtomFamilySelectorValue(
7076
recordStoreRecordsSelector,
@@ -107,10 +113,6 @@ export const useCommandMenuContextApi = (): CommandMenuContextApi => {
107113
? CommandMenuContextApiPageType.RECORD_PAGE
108114
: CommandMenuContextApiPageType.INDEX_PAGE;
109115

110-
const contextStoreNumberOfSelectedRecords = useAtomComponentStateValue(
111-
contextStoreNumberOfSelectedRecordsComponentState,
112-
);
113-
114116
const isSelectAll = contextStoreTargetedRecordsRule.mode === 'exclusion';
115117

116118
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { isDefined } from 'twenty-shared/utils';
2+
3+
import { commandMenuItemsDraftState } from '@/command-menu-item/server-items/edit/states/commandMenuItemsDraftState';
4+
import { commandMenuItemsSelector } from '@/command-menu-item/server-items/common/states/commandMenuItemsSelector';
5+
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
6+
7+
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
8+
9+
export const useCommandMenuItemsDraftState = () => {
10+
const commandMenuItems = useAtomStateValue(commandMenuItemsSelector);
11+
const commandMenuItemsDraft = useAtomStateValue(commandMenuItemsDraftState);
12+
13+
const isDirty =
14+
isDefined(commandMenuItemsDraft) &&
15+
!isDeeplyEqual(
16+
commandMenuItemsDraft.map(({ id, isPinned, position, shortLabel }) => ({
17+
id,
18+
isPinned,
19+
position,
20+
shortLabel,
21+
})),
22+
commandMenuItems.map(({ id, isPinned, position, shortLabel }) => ({
23+
id,
24+
isPinned,
25+
position,
26+
shortLabel,
27+
})),
28+
);
29+
30+
return {
31+
commandMenuItemsDraft,
32+
isDirty,
33+
};
34+
};

0 commit comments

Comments
 (0)