Refactor action menu (#7586)

Introduces effects to set the actionMenuEntries
This commit is contained in:
Raphaël Bosi
2024-10-11 15:25:35 +02:00
committed by GitHub
parent 9b9b34f991
commit 3761fbf86f
26 changed files with 447 additions and 319 deletions

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import { ActionMenuBarEntry } from '@/action-menu/components/ActionMenuBarEntry';
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
import { ActionBarHotkeyScope } from '@/action-menu/types/ActionBarHotKeyScope';
import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState';
@ -28,9 +28,13 @@ export const ActionMenuBar = () => {
);
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
actionMenuEntriesComponentSelector,
);
if (actionMenuEntries.length === 0) {
return null;
}
return (
<BottomBar
bottomBarId={`action-bar-${actionMenuId}`}

View File

@ -1,9 +1,9 @@
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const ActionMenuConfirmationModals = () => {
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
actionMenuEntriesComponentSelector,
);
return (

View File

@ -4,7 +4,7 @@ import { useRecoilValue } from 'recoil';
import { PositionType } from '../types/PositionType';
import { actionMenuDropdownPositionComponentState } from '@/action-menu/states/actionMenuDropdownPositionComponentState';
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
@ -36,7 +36,7 @@ const StyledContainerActionMenuDropdown = styled.div<StyledContainerProps>`
export const ActionMenuDropdown = () => {
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
actionMenuEntriesComponentSelector,
);
const actionMenuId = useAvailableComponentInstanceIdOrThrow(
@ -50,6 +50,10 @@ export const ActionMenuDropdown = () => {
),
);
if (actionMenuEntries.length === 0) {
return null;
}
//TODO: remove this
const width = actionMenuEntries.some(
(actionMenuEntry) => actionMenuEntry.label === 'Remove from favorites',

View File

@ -1,25 +0,0 @@
import { EmptyActionMenuEntriesEffect } from '@/action-menu/components/EmptyActionMenuEntriesEffect';
import { NonEmptyActionMenuEntriesEffect } from '@/action-menu/components/NonEmptyActionMenuEntriesEffect';
import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState';
import { useRecoilValue } from 'recoil';
export const ActionMenuEntriesProvider = () => {
//TODO: Refactor this
const contextStoreCurrentObjectMetadataId = useRecoilValue(
contextStoreCurrentObjectMetadataIdState,
);
return (
<>
{contextStoreCurrentObjectMetadataId ? (
<NonEmptyActionMenuEntriesEffect
contextStoreCurrentObjectMetadataId={
contextStoreCurrentObjectMetadataId
}
/>
) : (
<EmptyActionMenuEntriesEffect />
)}
</>
);
};

View File

@ -1,14 +0,0 @@
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useEffect } from 'react';
export const EmptyActionMenuEntriesEffect = () => {
const setActionMenuEntries = useSetRecoilComponentStateV2(
actionMenuEntriesComponentState,
);
useEffect(() => {
setActionMenuEntries([]);
}, [setActionMenuEntries]);
return null;
};

View File

@ -1,28 +0,0 @@
import { useComputeActionsBasedOnContextStore } from '@/action-menu/hooks/useComputeActionsBasedOnContextStore';
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useEffect } from 'react';
export const NonEmptyActionMenuEntriesEffect = ({
contextStoreCurrentObjectMetadataId,
}: {
contextStoreCurrentObjectMetadataId: string;
}) => {
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: contextStoreCurrentObjectMetadataId,
});
const { availableActionsInContext } = useComputeActionsBasedOnContextStore({
objectMetadataItem,
});
const setActionMenuEntries = useSetRecoilComponentStateV2(
actionMenuEntriesComponentState,
);
useEffect(() => {
setActionMenuEntries(availableActionsInContext);
}, [availableActionsInContext, setActionMenuEntries]);
return null;
};

View File

@ -25,18 +25,28 @@ const meta: Meta<typeof ActionMenuBar> = {
actionMenuEntriesComponentState.atomFamily({
instanceId: 'story-action-menu',
}),
[
{
label: 'Delete',
Icon: IconTrash,
onClick: deleteMock,
},
{
label: 'Mark as done',
Icon: IconCheckbox,
onClick: markAsDoneMock,
},
],
new Map([
[
'delete',
{
key: 'delete',
label: 'Delete',
position: 0,
Icon: IconTrash,
onClick: deleteMock,
},
],
[
'markAsDone',
{
key: 'markAsDone',
label: 'Mark as done',
position: 1,
Icon: IconCheckbox,
onClick: markAsDoneMock,
},
],
]),
);
set(
isBottomBarOpenedComponentState.atomFamily({

View File

@ -21,7 +21,9 @@ const markAsDoneMock = jest.fn();
export const Default: Story = {
args: {
entry: {
key: 'delete',
label: 'Delete',
position: 0,
Icon: IconTrash,
onClick: deleteMock,
},
@ -31,7 +33,9 @@ export const Default: Story = {
export const WithDangerAccent: Story = {
args: {
entry: {
key: 'delete',
label: 'Delete',
position: 0,
Icon: IconTrash,
onClick: deleteMock,
accent: 'danger',
@ -42,7 +46,9 @@ export const WithDangerAccent: Story = {
export const WithInteraction: Story = {
args: {
entry: {
key: 'markAsDone',
label: 'Mark as done',
position: 0,
Icon: IconCheckbox,
onClick: markAsDoneMock,
},

View File

@ -33,23 +33,38 @@ const meta: Meta<typeof ActionMenuDropdown> = {
actionMenuEntriesComponentState.atomFamily({
instanceId: 'story-action-menu',
}),
[
{
label: 'Delete',
Icon: IconTrash,
onClick: deleteMock,
},
{
label: 'Mark as done',
Icon: IconCheckbox,
onClick: markAsDoneMock,
},
{
label: 'Add to favorites',
Icon: IconHeart,
onClick: addToFavoritesMock,
},
],
new Map([
[
'delete',
{
key: 'delete',
label: 'Delete',
position: 0,
Icon: IconTrash,
onClick: deleteMock,
},
],
[
'markAsDone',
{
key: 'markAsDone',
label: 'Mark as done',
position: 1,
Icon: IconCheckbox,
onClick: markAsDoneMock,
},
],
[
'addToFavorites',
{
key: 'addToFavorites',
label: 'Add to favorites',
position: 2,
Icon: IconHeart,
onClick: addToFavoritesMock,
},
],
]),
);
set(
extractComponentState(