Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8414 add records selection context inside the command menu #8610

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
refactoring, bug fixes and create CommandMenuCommandsEffect
  • Loading branch information
bosiraphael committed Nov 20, 2024
commit cc460d51fe56eed1d27a74d771b16dadfd7e4419
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchS
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
import { Command, CommandType } from '@/command-menu/types/Command';
import { Company } from '@/companies/types/Company';
import {
ContextStoreTargetedRecordsRule,
contextStoreTargetedRecordsRuleComponentState,
} from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
Expand All @@ -31,7 +35,12 @@ import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { useMemo, useRef } from 'react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import {
useRecoilCallback,
useRecoilState,
useRecoilValue,
useSetRecoilState,
} from 'recoil';
import { Key } from 'ts-key-enum';
import { Avatar, IconNotes, IconSparkles, isDefined } from 'twenty-ui';
import { useDebounce } from 'use-debounce';
Expand Down Expand Up @@ -100,6 +109,25 @@ export const CommandMenu = () => {
const commandMenuCommands = useRecoilValue(commandMenuCommandsState);
const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu();

const mainContextStoreComponentInstanceId = useRecoilValue(
mainContextStoreComponentInstanceIdState,
);

const setContextStoreTargetedRecordsRule = useRecoilCallback(
({ set }) =>
(rule: ContextStoreTargetedRecordsRule) => {
if (isDefined(mainContextStoreComponentInstanceId)) {
set(
contextStoreTargetedRecordsRuleComponentState.atomFamily({
instanceId: mainContextStoreComponentInstanceId,
}),
rule,
);
}
},
[mainContextStoreComponentInstanceId],
);

const isMobile = useIsMobile();

useScopedHotkeys(
Expand All @@ -121,6 +149,23 @@ export const CommandMenu = () => {
[closeCommandMenu],
);

useScopedHotkeys(
[Key.Backspace, Key.Delete],
() => {
if (!isNonEmptyString(commandMenuSearch)) {
setContextStoreTargetedRecordsRule({
mode: 'selection',
selectedRecordIds: [],
});
}
},
AppHotkeyScope.CommandMenu,
[closeCommandMenu],
{
preventDefault: false,
},
);

const { loading: isPeopleLoading, records: people } =
useSearchRecords<Person>({
skip: !isCommandMenuOpened,
Expand Down Expand Up @@ -304,10 +349,6 @@ export const CommandMenu = () => {
isOpportunitiesLoading ||
isCompaniesLoading;

const mainContextStoreComponentInstanceId = useRecoilValue(
mainContextStoreComponentInstanceIdState,
);

return (
<>
{isCommandMenuOpened && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
import { commandMenuCommandsState } from '@/command-menu/states/commandMenuCommandsState';
import { computeCommandMenuCommands } from '@/command-menu/utils/computeCommandMenuCommands';
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-ui';

export const CommandMenuCommandsEffect = () => {
const mainContextStoreComponentInstanceId = useRecoilValue(
mainContextStoreComponentInstanceIdState,
);

const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentSelector,
mainContextStoreComponentInstanceId,
);

const setCommands = useSetRecoilState(commandMenuCommandsState);

useEffect(() => {
if (isDefined(mainContextStoreComponentInstanceId)) {
setCommands(computeCommandMenuCommands(actionMenuEntries));
}
}, [mainContextStoreComponentInstanceId, actionMenuEntries, setCommands]);

return null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const StyledAvatarWrapper = styled.div`
border-radius: ${({ theme }) => theme.border.radius.sm};
padding: ${({ theme }) => theme.spacing(0.5)};
border: 1px solid ${({ theme }) => theme.border.color.medium};
&:not(:first-child) {
&:not(:first-of-type) {
margin-left: -${({ theme }) => theme.spacing(1)};
}
`;
Expand Down Expand Up @@ -75,15 +75,15 @@ export const CommandMenuContextRecordChip = () => {

const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
contextStoreCurrentObjectMetadataIdComponentState,
mainContextStoreComponentInstanceId ?? undefined,
mainContextStoreComponentInstanceId,
);

const { objectMetadataItem } = useObjectMetadataItemById({
objectId: contextStoreCurrentObjectMetadataId ?? '',
});

const { records, loading, totalCount } = useContextStoreSelectedRecords(
mainContextStoreComponentInstanceId ?? undefined,
mainContextStoreComponentInstanceId,
);

if (loading || !totalCount) {
Expand All @@ -96,6 +96,7 @@ export const CommandMenuContextRecordChip = () => {
{records.map((record) => (
<CommandMenuContextRecordChipAvatars
objectMetadataItem={objectMetadataItem}
key={record.id}
record={record}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { isDefined } from '~/utils/isDefined';

import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
import { COMMAND_MENU_COMMANDS } from '@/command-menu/constants/CommandMenuCommands';
import { computeCommandMenuCommands } from '@/command-menu/utils/computeCommandMenuCommands';
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ALL_ICONS } from '@ui/display/icon/providers/internal/AllIcons';
Expand All @@ -37,39 +38,17 @@ export const useCommandMenu = () => {
({ snapshot }) =>
() => {
if (isDefined(mainContextStoreComponentInstanceId)) {
const actionMenuEntries = snapshot.getLoadable(
actionMenuEntriesComponentSelector.selectorFamily({
instanceId: mainContextStoreComponentInstanceId,
}),
);

const commands = Object.values(COMMAND_MENU_COMMANDS);

const actionCommands = actionMenuEntries
.getValue()
?.filter((actionMenuEntry) => actionMenuEntry.type === 'standard')
?.map((actionMenuEntry) => ({
id: actionMenuEntry.key,
label: actionMenuEntry.label,
Icon: actionMenuEntry.Icon,
onCommandClick: actionMenuEntry.onClick,
type: CommandType.StandardAction,
}));

const workflowRunCommands = actionMenuEntries
.getValue()
?.filter(
(actionMenuEntry) => actionMenuEntry.type === 'workflow-run',
const actionMenuEntries = snapshot
.getLoadable(
actionMenuEntriesComponentSelector.selectorFamily({
instanceId: mainContextStoreComponentInstanceId,
}),
)
?.map((actionMenuEntry) => ({
id: actionMenuEntry.key,
label: actionMenuEntry.label,
Icon: actionMenuEntry.Icon,
onCommandClick: actionMenuEntry.onClick,
type: CommandType.WorkflowRun,
}));

setCommands([...commands, ...actionCommands, ...workflowRunCommands]);
.getValue();

const commands = computeCommandMenuCommands(actionMenuEntries);

setCommands(commands);
}

setIsCommandMenuOpened(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
import { COMMAND_MENU_COMMANDS } from '@/command-menu/constants/CommandMenuCommands';
import { CommandType } from '@/command-menu/types/Command';

export const computeCommandMenuCommands = (
actionMenuEntries: ActionMenuEntry[],
) => {
const commands = Object.values(COMMAND_MENU_COMMANDS);

const actionCommands = actionMenuEntries
?.filter((actionMenuEntry) => actionMenuEntry.type === 'standard')
?.map((actionMenuEntry) => ({
id: actionMenuEntry.key,
label: actionMenuEntry.label,
Icon: actionMenuEntry.Icon,
onCommandClick: actionMenuEntry.onClick,
type: CommandType.StandardAction,
}));

const workflowRunCommands = actionMenuEntries
?.filter((actionMenuEntry) => actionMenuEntry.type === 'workflow-run')
?.map((actionMenuEntry) => ({
id: actionMenuEntry.key,
label: actionMenuEntry.label,
Icon: actionMenuEntry.Icon,
onCommandClick: actionMenuEntry.onClick,
type: CommandType.WorkflowRun,
}));

return [...commands, ...actionCommands, ...workflowRunCommands];
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export const MainContextStoreComponentInstanceIdSetterEffect = () => {
const context = useContext(ContextStoreComponentInstanceContext);

useEffect(() => {
setMainContextStoreComponentInstanceId(context?.instanceId ?? null);
setMainContextStoreComponentInstanceId(context?.instanceId ?? 'app');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make a constant


return () => {
setMainContextStoreComponentInstanceId(null);
setMainContextStoreComponentInstanceId('app');
};
}, [context, setMainContextStoreComponentInstanceId]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { createState } from 'twenty-ui';

export const mainContextStoreComponentInstanceIdState = createState<
string | null
>({
export const mainContextStoreComponentInstanceIdState = createState<string>({
key: 'mainContextStoreComponentInstanceIdState',
defaultValue: null,
defaultValue: 'app',
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AuthModal } from '@/auth/components/AuthModal';
import { CommandMenu } from '@/command-menu/components/CommandMenu';
import { CommandMenuCommandsEffect } from '@/command-menu/components/CommandMenuCommandsEffect';
import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary';
import { KeyboardShortcutMenu } from '@/keyboard-shortcut-menu/components/KeyboardShortcutMenu';
import { AppNavigationDrawer } from '@/navigation/components/AppNavigationDrawer';
Expand Down Expand Up @@ -80,6 +81,7 @@ export const DefaultLayout = () => {
`}
/>
<StyledLayout>
<CommandMenuCommandsEffect />
<CommandMenu />
<KeyboardShortcutMenu />

Expand Down