Fix search date suggestion crash (#26476)

* Fix search date suggestion crash

* Fix tests

* Improve snapshots

* Fix snapshot
Этот коммит содержится в:
Daniel Espino García
2024-03-21 09:50:12 +01:00
коммит произвёл GitHub
родитель 1383d51436
Коммит 8e43d45b3f
9 изменённых файлов: 31 добавлений и 100 удалений

Просмотреть файл

@@ -24,4 +24,4 @@ function mapStateToProps(state: GlobalState) {
}; };
} }
export default connect(mapStateToProps)(SearchDateSuggestion); export default connect(mapStateToProps, null, null, {forwardRef: true})(SearchDateSuggestion);

Просмотреть файл

@@ -15,9 +15,9 @@ import 'react-day-picker/dist/style.css';
type Props = SuggestionProps<never> & { type Props = SuggestionProps<never> & {
currentDate?: Date; currentDate?: Date;
handleEscape: () => void; handleEscape?: () => void;
locale: string; locale: string;
preventClose: () => void; preventClose?: () => void;
} }
export default class SearchDateSuggestion extends React.PureComponent<Props> { export default class SearchDateSuggestion extends React.PureComponent<Props> {
@@ -36,7 +36,7 @@ export default class SearchDateSuggestion extends React.PureComponent<Props> {
if (Keyboard.isKeyPressed(e, Constants.KeyCodes.DOWN) && document.activeElement?.id === 'searchBox') { if (Keyboard.isKeyPressed(e, Constants.KeyCodes.DOWN) && document.activeElement?.id === 'searchBox') {
this.setState({datePickerFocused: true}); this.setState({datePickerFocused: true});
} else if (Keyboard.isKeyPressed(e, Constants.KeyCodes.ESCAPE)) { } else if (Keyboard.isKeyPressed(e, Constants.KeyCodes.ESCAPE)) {
this.props.handleEscape(); this.props.handleEscape?.();
} }
}; };

Просмотреть файл

@@ -10,6 +10,7 @@ import Popover from 'components/widgets/popover';
import Constants from 'utils/constants'; import Constants from 'utils/constants';
import type {UserProfile} from './command_provider/app_command_parser/app_command_parser_dependencies'; import type {UserProfile} from './command_provider/app_command_parser/app_command_parser_dependencies';
import type {Props} from './suggestion_list';
import SuggestionList from './suggestion_list'; import SuggestionList from './suggestion_list';
interface Item extends UserProfile { interface Item extends UserProfile {
@@ -18,34 +19,6 @@ interface Item extends UserProfile {
name: string; name: string;
} }
interface Props {
ariaLiveRef?: React.RefObject<HTMLDivElement>;
inputRef?: React.RefObject<HTMLInputElement>;
open: boolean;
position?: 'top' | 'bottom';
renderDividers?: string[];
renderNoResults?: boolean;
onCompleteWord: (term: string, matchedPretext: string, e?: React.KeyboardEventHandler<HTMLDivElement>) => boolean;
preventClose?: () => void;
onItemHover: (term: string) => void;
pretext: string;
cleared: boolean;
matchedPretext: string[];
items: any[];
terms: string[];
selection: string;
components: Array<React.FunctionComponent<any>>;
wrapperHeight?: number;
// suggestionBoxAlgn is an optional object that can be passed to align the SuggestionList with the keyboard caret
// as the user is typing.
suggestionBoxAlgn?: {
lineHeight: number;
pixelsToMoveX: number;
pixelsToMoveY: number;
};
}
export default class SearchSuggestionList extends SuggestionList { export default class SearchSuggestionList extends SuggestionList {
popoverRef: React.RefObject<BSPopover>; popoverRef: React.RefObject<BSPopover>;
itemsContainerRef: React.RefObject<HTMLDivElement>; itemsContainerRef: React.RefObject<HTMLDivElement>;

Просмотреть файл

@@ -6,8 +6,12 @@ import React, {memo} from 'react';
import Popover from 'components/widgets/popover'; import Popover from 'components/widgets/popover';
type SuggestionItem = { type SuggestionItem = {
date: string;
label: string;
}
type SuggestionItemProps = {
key: string; key: string;
ref: string;
item: SuggestionItem; item: SuggestionItem;
term: string; term: string;
matchedPretext: string; matchedPretext: string;
@@ -24,7 +28,7 @@ type Props = {
terms: string[]; terms: string[];
preventClose: () => void; preventClose: () => void;
handleEscape: () => void; handleEscape: () => void;
components: Array<React.ComponentType<SuggestionItem>>; components: Array<React.ComponentType<SuggestionItemProps>>;
} }
const SuggestionDate = ({ const SuggestionDate = ({
@@ -54,7 +58,6 @@ const SuggestionDate = ({
> >
<Component <Component
key={term} key={term}
ref={term}
item={item} item={item}
term={term} term={term}
matchedPretext={matchedPretext[0]} matchedPretext={matchedPretext[0]}

Просмотреть файл

@@ -12,7 +12,7 @@ import LoadingSpinner from 'components/widgets/loading/loading_spinner';
import {Constants} from 'utils/constants'; import {Constants} from 'utils/constants';
import {isEmptyObject} from 'utils/utils'; import {isEmptyObject} from 'utils/utils';
interface Props { export interface Props {
ariaLiveRef?: React.RefObject<HTMLDivElement>; ariaLiveRef?: React.RefObject<HTMLDivElement>;
inputRef?: React.RefObject<HTMLDivElement>; inputRef?: React.RefObject<HTMLDivElement>;
open: boolean; open: boolean;
@@ -28,7 +28,7 @@ interface Props {
items: any[]; items: any[];
terms: string[]; terms: string[];
selection: string; selection: string;
components: Array<React.FunctionComponent<any>>; components: Array<React.ComponentType<any>>;
wrapperHeight?: number; wrapperHeight?: number;
// suggestionBoxAlgn is an optional object that can be passed to align the SuggestionList with the keyboard caret // suggestionBoxAlgn is an optional object that can be passed to align the SuggestionList with the keyboard caret

Просмотреть файл

@@ -56,7 +56,6 @@ exports[`component/user_group_popover should match snapshot 1`] = `
}, },
} }
} }
canManageGroup={true}
group={ group={
Object { Object {
"allow_reference": true, "allow_reference": true,
@@ -79,49 +78,8 @@ exports[`component/user_group_popover should match snapshot 1`] = `
searchTerm="" searchTerm=""
showUserOverlay={[MockFunction]} showUserOverlay={[MockFunction]}
> >
<Memo(Popover) <Popover
actions={
Object {
"openModal": [MockFunction],
"searchProfiles": [MockFunction],
"setPopoverSearchTerm": [MockFunction] {
"calls": Array [
Array [
"",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
}
}
canManageGroup={true}
group={
Object {
"allow_reference": true,
"create_at": 1,
"delete_at": 0,
"description": "",
"display_name": "group_display_name",
"has_syncables": false,
"id": "group1",
"member_count": 15,
"name": "group_name",
"remote_id": "",
"scheme_admin": false,
"source": "",
"update_at": 1,
}
}
hide={[MockFunction]}
id="user-group-popover" id="user-group-popover"
returnFocus={[MockFunction]}
searchTerm=""
showUserOverlay={[MockFunction]}
> >
<Popover <Popover
bsClass="popover" bsClass="popover"
@@ -2126,7 +2084,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
</div> </div>
</div> </div>
</Popover> </Popover>
</Memo(Popover)> </Popover>
</Memo(UserGroupPopover)> </Memo(UserGroupPopover)>
</Router> </Router>
</BrowserRouter> </BrowserRouter>

Просмотреть файл

@@ -2,6 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import type {ReactWrapper} from 'enzyme'; import type {ReactWrapper} from 'enzyme';
import type {ComponentProps} from 'react';
import React from 'react'; import React from 'react';
import {Provider} from 'react-redux'; import {Provider} from 'react-redux';
import {BrowserRouter} from 'react-router-dom'; import {BrowserRouter} from 'react-router-dom';
@@ -100,10 +101,9 @@ describe('component/user_group_popover', () => {
}, },
}; };
const baseProps = { const baseProps: ComponentProps<typeof UserGroupPopover> = {
searchTerm: '', searchTerm: '',
group: group1, group: group1,
canManageGroup: true,
showUserOverlay: jest.fn(), showUserOverlay: jest.fn(),
hide: jest.fn(), hide: jest.fn(),
returnFocus: jest.fn(), returnFocus: jest.fn(),

Просмотреть файл

@@ -64,16 +64,14 @@ export type Props = {
}; };
} }
const UserGroupPopover = (props: Props) => { const UserGroupPopover = ({
const { actions,
group, group,
actions, hide,
hide, returnFocus,
returnFocus, searchTerm,
searchTerm, showUserOverlay,
showUserOverlay, }: Props) => {
} = props;
const {formatMessage} = useIntl(); const {formatMessage} = useIntl();
const closeRef = useRef<HTMLButtonElement>(null); const closeRef = useRef<HTMLButtonElement>(null);
@@ -183,7 +181,6 @@ const UserGroupPopover = (props: Props) => {
return ( return (
<Popover <Popover
{...props}
id='user-group-popover' id='user-group-popover'
> >
{tabCatcher} {tabCatcher}

Просмотреть файл

@@ -19,10 +19,9 @@ interface Props {
style?: React.CSSProperties; style?: React.CSSProperties;
onMouseOut?: React.MouseEventHandler<BSPopover>; // didn't find a better way to satisfy typing, so for now we have a slight 'bootstrap leakage' onMouseOut?: React.MouseEventHandler<BSPopover>; // didn't find a better way to satisfy typing, so for now we have a slight 'bootstrap leakage'
onMouseOver?: React.MouseEventHandler<BSPopover>; onMouseOver?: React.MouseEventHandler<BSPopover>;
ref?: React.Ref<BSPopover>;
} }
const Popover = ({ const Popover = React.forwardRef<BSPopover, Props>(({
placement = 'right', placement = 'right',
popoverSize = 'sm', popoverSize = 'sm',
children, children,
@@ -33,8 +32,7 @@ const Popover = ({
onMouseOver, onMouseOver,
className, className,
style, style,
ref, }, ref?) => {
}: Props) => {
return ( return (
<BSPopover <BSPopover
id={id} id={id}
@@ -45,13 +43,15 @@ const Popover = ({
bsClass='popover' bsClass='popover'
title={title} title={title}
bsSize={popoverSize && SizeMap[popoverSize] as BSSizes} // map our sizes to bootstrap bsSize={popoverSize && SizeMap[popoverSize] as BSSizes} // map our sizes to bootstrap
onMouseOut={onMouseOut!} onMouseOut={onMouseOut}
onMouseOver={onMouseOver} onMouseOver={onMouseOver}
ref={ref} ref={ref}
> >
{children} {children}
</BSPopover> </BSPopover>
); );
}; });
Popover.displayName = 'Popover';
export default React.memo(Popover); export default React.memo(Popover);