New TitleInput UI component for side panel (#11192)
# Description I previously introduced the `RecordTitleCell` component, but it was coupled with the field context, so it was only usable for record fields. This PR: - Introduces a new component `TitleInput` for side panel pages which needed to have an editable title which wasn't a record field. - Fixes the hotkey scope problem with the workflow step page title - Introduces a new hook `useUpdateCommandMenuPageInfo`, to update the side panel page title and icon. - Fixes workflow side panel UI - Adds jest tests and stories # Video https://github.com/user-attachments/assets/c501245c-4492-4351-b761-05b5abc4bd14
This commit is contained in:
@ -0,0 +1,135 @@
|
||||
import { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateCommandMenuPageInfo';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { RecoilRoot, useRecoilValue } from 'recoil';
|
||||
import { IconArrowDown, IconDotsVertical } from 'twenty-ui';
|
||||
|
||||
const mockedPageInfo = {
|
||||
title: 'Initial Title',
|
||||
Icon: IconDotsVertical,
|
||||
instanceId: 'test-instance',
|
||||
};
|
||||
|
||||
const mockedNavigationStack = [
|
||||
{
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'Initial Title',
|
||||
pageIcon: IconDotsVertical,
|
||||
pageId: 'test-page-id',
|
||||
},
|
||||
];
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot
|
||||
initializeState={({ set }) => {
|
||||
set(commandMenuNavigationStackState, mockedNavigationStack);
|
||||
set(commandMenuPageInfoState, mockedPageInfo);
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
describe('useUpdateCommandMenuPageInfo', () => {
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { updateCommandMenuPageInfo } = useUpdateCommandMenuPageInfo();
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState);
|
||||
|
||||
return {
|
||||
updateCommandMenuPageInfo,
|
||||
commandMenuNavigationStack,
|
||||
commandMenuPageInfo,
|
||||
};
|
||||
},
|
||||
{ wrapper: Wrapper },
|
||||
);
|
||||
|
||||
return {
|
||||
result,
|
||||
};
|
||||
};
|
||||
|
||||
it('should update command menu page info with new title and icon', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.updateCommandMenuPageInfo({
|
||||
pageTitle: 'New Title',
|
||||
pageIcon: IconArrowDown,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'New Title',
|
||||
pageIcon: IconArrowDown,
|
||||
pageId: 'test-page-id',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'New Title',
|
||||
Icon: IconArrowDown,
|
||||
instanceId: 'test-instance',
|
||||
});
|
||||
});
|
||||
|
||||
it('should update command menu page info with new title', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.updateCommandMenuPageInfo({
|
||||
pageTitle: 'New Title',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'New Title',
|
||||
pageIcon: IconDotsVertical,
|
||||
pageId: 'test-page-id',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'New Title',
|
||||
Icon: IconDotsVertical,
|
||||
instanceId: 'test-instance',
|
||||
});
|
||||
});
|
||||
|
||||
it('should update command menu page info with new icon', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.updateCommandMenuPageInfo({
|
||||
pageIcon: IconArrowDown,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'Initial Title',
|
||||
pageIcon: IconArrowDown,
|
||||
pageId: 'test-page-id',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Initial Title',
|
||||
Icon: IconArrowDown,
|
||||
instanceId: 'test-instance',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,57 @@
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { IconComponent, IconDotsVertical } from 'twenty-ui';
|
||||
|
||||
export const useUpdateCommandMenuPageInfo = () => {
|
||||
const updateCommandMenuPageInfo = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
({
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
}: {
|
||||
pageTitle?: string;
|
||||
pageIcon?: IconComponent;
|
||||
}) => {
|
||||
const commandMenuPageInfo = snapshot
|
||||
.getLoadable(commandMenuPageInfoState)
|
||||
.getValue();
|
||||
|
||||
const newCommandMenuPageInfo = {
|
||||
...commandMenuPageInfo,
|
||||
title: pageTitle ?? commandMenuPageInfo.title ?? '',
|
||||
Icon: pageIcon ?? commandMenuPageInfo.Icon ?? IconDotsVertical,
|
||||
};
|
||||
|
||||
set(commandMenuPageInfoState, newCommandMenuPageInfo);
|
||||
|
||||
const commandMenuNavigationStack = snapshot
|
||||
.getLoadable(commandMenuNavigationStackState)
|
||||
.getValue();
|
||||
|
||||
const lastCommandMenuNavigationStackItem =
|
||||
commandMenuNavigationStack.at(-1);
|
||||
|
||||
if (!lastCommandMenuNavigationStackItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newCommandMenuNavigationStack = [
|
||||
...commandMenuNavigationStack.slice(0, -1),
|
||||
{
|
||||
page: lastCommandMenuNavigationStackItem.page,
|
||||
pageTitle: newCommandMenuPageInfo.title,
|
||||
pageIcon: newCommandMenuPageInfo.Icon,
|
||||
pageId: lastCommandMenuNavigationStackItem.pageId,
|
||||
},
|
||||
];
|
||||
|
||||
set(commandMenuNavigationStackState, newCommandMenuNavigationStack);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
updateCommandMenuPageInfo,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user