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>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
a93a01fa8f
Коммит
1f525550a5
@@ -7,6 +7,8 @@ import {shallow} from 'enzyme';
|
||||
import AccessHistoryModal from 'components/access_history_modal/access_history_modal';
|
||||
import AuditTable from 'components/audit_table';
|
||||
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', () => {
|
||||
const baseProps = {
|
||||
@@ -38,26 +40,23 @@ describe('components/AccessHistoryModal', () => {
|
||||
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 = {
|
||||
getUserAudits: jest.fn(),
|
||||
};
|
||||
const props = {...baseProps, actions};
|
||||
const wrapper = shallow<AccessHistoryModal>(
|
||||
<AccessHistoryModal {...props}/>,
|
||||
);
|
||||
const view = render(withIntl(<AccessHistoryModal {...props}/>));
|
||||
|
||||
wrapper.instance().onShow();
|
||||
expect(actions.getUserAudits).toHaveBeenCalledTimes(2);
|
||||
expect(actions.getUserAudits).toHaveBeenCalledTimes(1);
|
||||
const newProps = {...props, currentUserId: 'foo'};
|
||||
view.rerender(withIntl(<AccessHistoryModal {...newProps}/>));
|
||||
expect(actions.getUserAudits).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should match state when onHide is called', () => {
|
||||
const wrapper = shallow<AccessHistoryModal>(
|
||||
<AccessHistoryModal {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({show: true});
|
||||
wrapper.instance().onHide();
|
||||
expect(wrapper.state('show')).toEqual(false);
|
||||
test('should hide', async () => {
|
||||
render(withIntl(<AccessHistoryModal {...baseProps}/>));
|
||||
await waitFor(() => screen.getByText('Access History'));
|
||||
fireEvent.click(screen.getByLabelText('Close'));
|
||||
await waitForElementToBeRemoved(() => screen.getByText('Access History'));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,98 +1,92 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import AuditTable from 'components/audit_table';
|
||||
import LoadingScreen from 'components/loading_screen';
|
||||
import {Audit} from '@mattermost/types/audits';
|
||||
|
||||
type Props = {
|
||||
onHide: () => void;
|
||||
actions: {
|
||||
getUserAudits: (userId: string, page?: number, perPage?: number) => void;
|
||||
};
|
||||
userAudits: any[];
|
||||
userAudits: Audit[];
|
||||
currentUserId: string;
|
||||
}
|
||||
|
||||
type State = {
|
||||
show: boolean;
|
||||
}
|
||||
const AccessHistoryModal = ({
|
||||
actions: {
|
||||
getUserAudits,
|
||||
},
|
||||
currentUserId,
|
||||
onHide,
|
||||
userAudits,
|
||||
}: Props) => {
|
||||
const [show, setShow] = useState(true);
|
||||
|
||||
export default class AccessHistoryModal extends React.PureComponent<Props, State> {
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
const onCloseClick = useCallback(() => {
|
||||
setShow(false);
|
||||
}, []);
|
||||
|
||||
this.state = {
|
||||
show: true,
|
||||
};
|
||||
}
|
||||
useEffect(() => {
|
||||
getUserAudits(currentUserId, 0, 200);
|
||||
}, []);
|
||||
|
||||
public onShow = () => { // public for testing
|
||||
this.props.actions.getUserAudits(this.props.currentUserId, 0, 200);
|
||||
};
|
||||
|
||||
public onHide = () => { // public for testing
|
||||
this.setState({show: false});
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
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>
|
||||
let content;
|
||||
if (userAudits.length === 0) {
|
||||
content = (<LoadingScreen/>);
|
||||
} else {
|
||||
content = (
|
||||
<AuditTable
|
||||
audits={userAudits}
|
||||
showIp={true}
|
||||
showSession={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"WrappedComponent": [Function],
|
||||
"WrappedComponent": Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
}
|
||||
@@ -303,7 +307,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
||||
dialogType={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"WrappedComponent": [Function],
|
||||
"WrappedComponent": Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
}
|
||||
@@ -481,7 +489,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
||||
dialogType={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"WrappedComponent": [Function],
|
||||
"WrappedComponent": Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
}
|
||||
@@ -659,7 +671,11 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
||||
dialogType={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"WrappedComponent": [Function],
|
||||
"WrappedComponent": Object {
|
||||
"$$typeof": Symbol(react.memo),
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"compare": null,
|
||||
"type": [Function],
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user