Migrate access history modal to functional component (#24210)

* Migrate access history modal to functional component

* Fix tests

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Daniel Espino García
2023-08-14 14:20:07 +02:00
коммит произвёл GitHub
родитель a93a01fa8f
Коммит 1f525550a5
3 изменённых файлов: 103 добавлений и 94 удалений

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

@@ -7,6 +7,8 @@ import {shallow} from 'enzyme';
import AccessHistoryModal from 'components/access_history_modal/access_history_modal'; import AccessHistoryModal from 'components/access_history_modal/access_history_modal';
import AuditTable from 'components/audit_table'; import AuditTable from 'components/audit_table';
import LoadingScreen from 'components/loading_screen'; import LoadingScreen from 'components/loading_screen';
import {withIntl} from 'tests/helpers/intl-test-helper';
import {fireEvent, screen, render, waitForElementToBeRemoved, waitFor} from '@testing-library/react';
describe('components/AccessHistoryModal', () => { describe('components/AccessHistoryModal', () => {
const baseProps = { const baseProps = {
@@ -38,26 +40,23 @@ describe('components/AccessHistoryModal', () => {
expect(wrapper.find(AuditTable).exists()).toBe(true); expect(wrapper.find(AuditTable).exists()).toBe(true);
}); });
test('should have called actions.getUserAudits when onShow is called', () => { test('should have called actions.getUserAudits only when first rendered', () => {
const actions = { const actions = {
getUserAudits: jest.fn(), getUserAudits: jest.fn(),
}; };
const props = {...baseProps, actions}; const props = {...baseProps, actions};
const wrapper = shallow<AccessHistoryModal>( const view = render(withIntl(<AccessHistoryModal {...props}/>));
<AccessHistoryModal {...props}/>,
);
wrapper.instance().onShow(); expect(actions.getUserAudits).toHaveBeenCalledTimes(1);
expect(actions.getUserAudits).toHaveBeenCalledTimes(2); const newProps = {...props, currentUserId: 'foo'};
view.rerender(withIntl(<AccessHistoryModal {...newProps}/>));
expect(actions.getUserAudits).toHaveBeenCalledTimes(1);
}); });
test('should match state when onHide is called', () => { test('should hide', async () => {
const wrapper = shallow<AccessHistoryModal>( render(withIntl(<AccessHistoryModal {...baseProps}/>));
<AccessHistoryModal {...baseProps}/>, await waitFor(() => screen.getByText('Access History'));
); fireEvent.click(screen.getByLabelText('Close'));
await waitForElementToBeRemoved(() => screen.getByText('Access History'));
wrapper.setState({show: true});
wrapper.instance().onHide();
expect(wrapper.state('show')).toEqual(false);
}); });
}); });

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

@@ -1,98 +1,92 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'; import React, {useCallback, useEffect, useState} from 'react';
import {Modal} from 'react-bootstrap'; import {Modal} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import AuditTable from 'components/audit_table'; import AuditTable from 'components/audit_table';
import LoadingScreen from 'components/loading_screen'; import LoadingScreen from 'components/loading_screen';
import {Audit} from '@mattermost/types/audits';
type Props = { type Props = {
onHide: () => void; onHide: () => void;
actions: { actions: {
getUserAudits: (userId: string, page?: number, perPage?: number) => void; getUserAudits: (userId: string, page?: number, perPage?: number) => void;
}; };
userAudits: any[]; userAudits: Audit[];
currentUserId: string; currentUserId: string;
} }
type State = { const AccessHistoryModal = ({
show: boolean; actions: {
} getUserAudits,
},
currentUserId,
onHide,
userAudits,
}: Props) => {
const [show, setShow] = useState(true);
export default class AccessHistoryModal extends React.PureComponent<Props, State> { const onCloseClick = useCallback(() => {
public constructor(props: Props) { setShow(false);
super(props); }, []);
this.state = { useEffect(() => {
show: true, getUserAudits(currentUserId, 0, 200);
}; }, []);
}
public onShow = () => { // public for testing let content;
this.props.actions.getUserAudits(this.props.currentUserId, 0, 200); if (userAudits.length === 0) {
}; content = (<LoadingScreen/>);
} else {
public onHide = () => { // public for testing content = (
this.setState({show: false}); <AuditTable
}; audits={userAudits}
showIp={true}
public componentDidMount() { showSession={true}
this.onShow(); />
}
public render() {
let content;
if (this.props.userAudits.length === 0) {
content = (<LoadingScreen/>);
} else {
content = (
<AuditTable
audits={this.props.userAudits}
showIp={true}
showSession={true}
/>
);
}
return (
<Modal
dialogClassName='a11y__modal modal--scroll'
show={this.state.show}
onHide={this.onHide}
onExited={this.props.onHide}
bsSize='large'
role='dialog'
aria-labelledby='accessHistoryModalLabel'
>
<Modal.Header closeButton={true}>
<Modal.Title
componentClass='h1'
id='accessHistoryModalLabel'
>
<FormattedMessage
id='access_history.title'
defaultMessage='Access History'
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
{content}
</Modal.Body>
<Modal.Footer className='modal-footer--invisible'>
<button
id='closeModalButton'
type='button'
className='btn btn-link'
>
<FormattedMessage
id='general_button.close'
defaultMessage='Close'
/>
</button>
</Modal.Footer>
</Modal>
); );
} }
}
return (
<Modal
dialogClassName='a11y__modal modal--scroll'
show={show}
onHide={onCloseClick}
onExited={onHide}
bsSize='large'
role='dialog'
aria-labelledby='accessHistoryModalLabel'
>
<Modal.Header closeButton={true}>
<Modal.Title
componentClass='h1'
id='accessHistoryModalLabel'
>
<FormattedMessage
id='access_history.title'
defaultMessage='Access History'
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
{content}
</Modal.Body>
<Modal.Footer className='modal-footer--invisible'>
<button
id='closeModalButton'
type='button'
className='btn btn-link'
>
<FormattedMessage
id='general_button.close'
defaultMessage='Close'
/>
</button>
</Modal.Footer>
</Modal>
);
};
export default React.memo(AccessHistoryModal);

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

@@ -125,7 +125,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
dialogType={ dialogType={
Object { Object {
"$$typeof": Symbol(react.memo), "$$typeof": Symbol(react.memo),
"WrappedComponent": [Function], "WrappedComponent": Object {
"$$typeof": Symbol(react.memo),
"compare": null,
"type": [Function],
},
"compare": null, "compare": null,
"type": [Function], "type": [Function],
} }
@@ -303,7 +307,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
dialogType={ dialogType={
Object { Object {
"$$typeof": Symbol(react.memo), "$$typeof": Symbol(react.memo),
"WrappedComponent": [Function], "WrappedComponent": Object {
"$$typeof": Symbol(react.memo),
"compare": null,
"type": [Function],
},
"compare": null, "compare": null,
"type": [Function], "type": [Function],
} }
@@ -481,7 +489,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
dialogType={ dialogType={
Object { Object {
"$$typeof": Symbol(react.memo), "$$typeof": Symbol(react.memo),
"WrappedComponent": [Function], "WrappedComponent": Object {
"$$typeof": Symbol(react.memo),
"compare": null,
"type": [Function],
},
"compare": null, "compare": null,
"type": [Function], "type": [Function],
} }
@@ -659,7 +671,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
dialogType={ dialogType={
Object { Object {
"$$typeof": Symbol(react.memo), "$$typeof": Symbol(react.memo),
"WrappedComponent": [Function], "WrappedComponent": Object {
"$$typeof": Symbol(react.memo),
"compare": null,
"type": [Function],
},
"compare": null, "compare": null,
"type": [Function], "type": [Function],
} }