-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Add workflow node actions and side panel controls #24411
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
Changes from 4 commits
ba02a6b
ca93eb8
996b6fb
079eadf
6ced764
9437116
fba170e
3666ea9
53b695c
723f496
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu'; | ||
| import { useLingui } from '@lingui/react/macro'; | ||
| import { IconX } from 'twenty-ui/icon'; | ||
| import { IconButtonWithTooltip } from 'twenty-ui/input'; | ||
|
|
||
| export const SidePanelCloseButton = () => { | ||
| const { t } = useLingui(); | ||
| const { closeSidePanelMenu } = useSidePanelMenu(); | ||
|
|
||
| const closeSidePanelLabel = t`Close side panel`; | ||
|
|
||
| return ( | ||
| <IconButtonWithTooltip | ||
| tooltipContent={closeSidePanelLabel} | ||
| Icon={IconX} | ||
| size="small" | ||
| variant="primary" | ||
| onClick={closeSidePanelMenu} | ||
| ariaLabel={closeSidePanelLabel} | ||
| /> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { type RefObject } from 'react'; | ||
| import { Key } from 'ts-key-enum'; | ||
|
|
||
| import { useGlobalHotkeys } from '@/ui/utilities/hotkey/hooks/useGlobalHotkeys'; | ||
|
|
||
| type SidePanelTopBarEscapeHotkeyEffectProps = { | ||
| inputRef: RefObject<HTMLInputElement | null>; | ||
| onEscape: () => void; | ||
| }; | ||
|
|
||
| export const SidePanelTopBarEscapeHotkeyEffect = ({ | ||
| inputRef, | ||
| onEscape, | ||
| }: SidePanelTopBarEscapeHotkeyEffectProps) => { | ||
| const handleEscape = () => { | ||
| if (document.activeElement === inputRef.current) { | ||
| return; | ||
| } | ||
|
|
||
| onEscape(); | ||
| }; | ||
|
|
||
| useGlobalHotkeys({ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RecordTableBodyEscapeHotkeyEffect (and the board/calendar ones) also listen for Escape on PageFocusId.RecordIndex and each side stops immediate propagation when it matches, so whichever registered first swallows the other — the table one even with no rows selected. On a record index with the panel open, which one should win, and is that deterministic today? |
||
| keys: [Key.Escape], | ||
| callback: handleEscape, | ||
| containsModifier: false, | ||
| dependencies: [handleEscape], | ||
| }); | ||
|
|
||
| return null; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import { render, screen } from '@testing-library/react'; | ||
| import userEvent from '@testing-library/user-event'; | ||
| import { createRef } from 'react'; | ||
|
|
||
| import { SidePanelTopBarEscapeHotkeyEffect } from '@/side-panel/components/SidePanelTopBarEscapeHotkeyEffect'; | ||
|
|
||
| describe('SidePanelTopBarEscapeHotkeyEffect', () => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Nit · Low-level · Dedicated .test.tsx on a render-null Effect component is a finding SidePanelTopBarEscapeHotkeyEffect is a side-effect-only component that renders null, so a standalone test asserting mocked globals is exactly the case the standard says to fold into the host; the SidePanelTopBar test already covers the escape-while-input-not-focused path. Delete this file and cover the effect through SidePanelTopBar.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed — host-level Escape coverage remains in |
||
| it('handles Escape only when the search input is not focused', async () => { | ||
| const inputRef = createRef<HTMLInputElement>(); | ||
| const handleEscape = jest.fn(); | ||
|
|
||
| render( | ||
| <> | ||
| <input aria-label="Search" ref={inputRef} /> | ||
| <button type="button">Outside</button> | ||
| <SidePanelTopBarEscapeHotkeyEffect | ||
| inputRef={inputRef} | ||
| onEscape={handleEscape} | ||
| /> | ||
| </>, | ||
| ); | ||
|
|
||
| const input = screen.getByRole('textbox', { name: 'Search' }); | ||
| const outsideButton = screen.getByRole('button', { name: 'Outside' }); | ||
|
|
||
| await userEvent.click(input); | ||
| await userEvent.keyboard('{Escape}'); | ||
|
|
||
| expect(handleEscape).not.toHaveBeenCalled(); | ||
|
|
||
| await userEvent.click(outsideButton); | ||
| await userEvent.keyboard('{Escape}'); | ||
|
|
||
| expect(handleEscape).toHaveBeenCalledTimes(1); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On non-mac this renders "Expand | Ctrl⏎" with Ctrl glued to ⏎ — want a separator like the hotkeys arrays elsewhere?