Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
sysadmin
mattermost
mattermost-webapp
Commits
f27aa4bb
Commit
f27aa4bb
authored
Jun 06, 2018
by
Saturnino Abril
Committed by
Carlos Tadeu Panato Junior
Jun 06, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix missing users' status indicators on more DM modal (#1279)
parent
725552c0
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
304 additions
and
2 deletions
+304
-2
components/more_direct_channels/index.js
components/more_direct_channels/index.js
+7
-1
components/more_direct_channels/more_direct_channels.jsx
components/more_direct_channels/more_direct_channels.jsx
+20
-1
tests/components/__snapshots__/more_direct_channels.test.jsx.snap
...mponents/__snapshots__/more_direct_channels.test.jsx.snap
+146
-0
tests/components/more_direct_channels.test.jsx
tests/components/more_direct_channels.test.jsx
+131
-0
No files found.
components/more_direct_channels/index.js
View file @
f27aa4bb
...
...
@@ -3,7 +3,12 @@
import
{
connect
}
from
'
react-redux
'
;
import
{
bindActionCreators
}
from
'
redux
'
;
import
{
getProfiles
,
getProfilesInTeam
,
searchProfiles
}
from
'
mattermost-redux/actions/users
'
;
import
{
getProfiles
,
getProfilesInTeam
,
getStatusesByIds
,
searchProfiles
,
}
from
'
mattermost-redux/actions/users
'
;
import
{
getCurrentUserId
,
getProfiles
as
selectProfiles
,
...
...
@@ -62,6 +67,7 @@ function mapDispatchToProps(dispatch) {
actions
:
bindActionCreators
({
getProfiles
,
getProfilesInTeam
,
getStatusesByIds
,
searchProfiles
,
setModalSearchTerm
,
},
dispatch
),
...
...
components/more_direct_channels/more_direct_channels.jsx
View file @
f27aa4bb
...
...
@@ -48,6 +48,7 @@ export default class MoreDirectChannels extends React.Component {
actions
:
PropTypes
.
shape
({
getProfiles
:
PropTypes
.
func
.
isRequired
,
getProfilesInTeam
:
PropTypes
.
func
.
isRequired
,
getStatusesByIds
:
PropTypes
.
func
.
isRequired
,
searchProfiles
:
PropTypes
.
func
.
isRequired
,
setModalSearchTerm
:
PropTypes
.
func
.
isRequired
,
}).
isRequired
,
...
...
@@ -83,6 +84,7 @@ export default class MoreDirectChannels extends React.Component {
componentDidMount
()
{
this
.
getUserProfiles
();
this
.
loadProfilesMissingStatus
(
this
.
props
.
users
,
this
.
props
.
statuses
);
}
UNSAFE_componentWillReceiveProps
(
nextProps
)
{
// eslint-disable-line camelcase
...
...
@@ -109,6 +111,23 @@ export default class MoreDirectChannels extends React.Component {
);
}
}
if
(
this
.
props
.
users
.
length
!==
nextProps
.
users
.
length
||
Object
.
keys
(
this
.
props
.
statuses
).
length
!==
Object
.
keys
(
nextProps
.
statuses
).
length
)
{
this
.
loadProfilesMissingStatus
(
nextProps
.
users
,
nextProps
.
statuses
);
}
}
loadProfilesMissingStatus
=
(
users
=
[],
statuses
=
{})
=>
{
const
missingStatusByIds
=
users
.
filter
((
user
)
=>
!
statuses
[
user
.
id
]).
map
((
user
)
=>
user
.
id
);
if
(
missingStatusByIds
.
length
>
0
)
{
this
.
props
.
actions
.
getStatusesByIds
(
missingStatusByIds
);
}
}
handleHide
=
()
=>
{
...
...
@@ -282,7 +301,7 @@ export default class MoreDirectChannels extends React.Component {
}
handleSubmitImmediatelyOn
=
(
value
)
=>
{
return
value
.
id
===
this
.
props
.
currentUserId
||
value
.
delete_at
;
return
value
.
id
===
this
.
props
.
currentUserId
||
Boolean
(
value
.
delete_at
)
;
}
render
()
{
...
...
tests/components/__snapshots__/more_direct_channels.test.jsx.snap
0 → 100644
View file @
f27aa4bb
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/MoreDirectChannels should match renderOption snapshot 1`] = `
<div
className="more-modal__row clickable more-modal__row--selected"
onClick={[Function]}
>
<ProfilePicture
hasMention={false}
height="32"
isRHS={false}
src="/api/v4/users/user_id_1/image"
status="online"
width="32"
/>
<div
className="more-modal__details"
>
<div
className="more-modal__name"
>
@undefined
</div>
<div
className="more-modal__description"
/>
</div>
<div
className="more-modal__actions"
>
<div
className="more-modal__actions--round"
>
<i
className="fa fa-plus"
/>
</div>
</div>
</div>
`;
exports[`components/MoreDirectChannels should match snapshot 1`] = `
<Modal
animation={true}
autoFocus={true}
backdrop={true}
bsClass="modal"
dialogClassName="more-modal more-direct-channels"
dialogComponentClass={[Function]}
enforceFocus={true}
keyboard={true}
manager={
ModalManager {
"add": [Function],
"containers": Array [],
"data": Array [],
"handleContainerOverflow": true,
"hideSiblingNodes": true,
"isTopModal": [Function],
"modals": Array [],
"remove": [Function],
}
}
onExited={[Function]}
onHide={[Function]}
renderBackdrop={[Function]}
restoreFocus={true}
show={true}
>
<ModalHeader
bsClass="modal-header"
closeButton={true}
closeLabel="Close"
>
<ModalTitle
bsClass="modal-title"
componentClass="h4"
>
<FormattedMessage
defaultMessage="Direct Messages"
id="more_direct_channels.title"
values={Object {}}
/>
</ModalTitle>
</ModalHeader>
<ModalBody
bsClass="modal-body"
componentClass="div"
>
<MultiSelect
buttonSubmitText="Go"
handleAdd={[Function]}
handleDelete={[Function]}
handleInput={[Function]}
handlePageChange={[Function]}
handleSubmit={[Function]}
key="moreDirectChannelsList"
loading={true}
maxValues={7}
numRemainingText={
<FormattedMessage
defaultMessage="Use ↑↓ to browse, ↵ to select. You can add {num, number} more {num, plural, one {person} other {people}}. "
id="multiselect.numPeopleRemaining"
values={
Object {
"num": 5,
}
}
/>
}
optionRenderer={[Function]}
options={
Array [
Object {
"delete_at": 0,
"id": "user_id_1",
},
Object {
"delete_at": 0,
"id": "user_id_2",
},
Object {
"delete_at": 0,
"id": "user_id_3",
},
]
}
perPage={50}
saving={false}
submitImmediatelyOn={[Function]}
valueKey="id"
valueRenderer={[Function]}
values={
Array [
Object {
"id": "user_id_1",
},
Object {
"id": "user_id_2",
},
]
}
/>
</ModalBody>
</Modal>
`;
tests/components/more_direct_channels.test.jsx
0 → 100644
View file @
f27aa4bb
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import
React
from
'
react
'
;
import
{
shallow
}
from
'
enzyme
'
;
import
MoreDirectChannels
from
'
components/more_direct_channels/more_direct_channels.jsx
'
;
jest
.
useFakeTimers
();
describe
(
'
components/MoreDirectChannels
'
,
()
=>
{
function
emptyFunction
()
{}
//eslint-disable-line no-empty-function
const
baseProps
=
{
currentUserId
:
'
current_user_id
'
,
currentTeamId
:
'
team_id
'
,
currentTeamName
:
'
team_name
'
,
searchTerm
:
''
,
users
:
[{
id
:
'
user_id_1
'
,
delete_at
:
0
},
{
id
:
'
user_id_2
'
,
delete_at
:
0
},
{
id
:
'
user_id_3
'
,
delete_at
:
0
}],
statuses
:
{
user_id_1
:
'
online
'
,
user_id_2
:
'
away
'
},
currentChannelMembers
:
[{
id
:
'
user_id_1
'
},
{
id
:
'
user_id_2
'
}],
isExistingChannel
:
false
,
restrictDirectMessage
:
'
any
'
,
onModalDismissed
:
emptyFunction
,
onHide
:
emptyFunction
,
actions
:
{
getProfiles
:
jest
.
fn
(()
=>
{
return
new
Promise
((
resolve
)
=>
{
process
.
nextTick
(()
=>
resolve
());
});
}),
getProfilesInTeam
:
emptyFunction
,
getStatusesByIds
:
emptyFunction
,
searchProfiles
:
emptyFunction
,
setModalSearchTerm
:
emptyFunction
,
},
};
test
(
'
should match snapshot
'
,
()
=>
{
const
props
=
{...
baseProps
,
actions
:
{...
baseProps
.
actions
,
getStatusesByIds
:
jest
.
fn
()}};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
expect
(
wrapper
).
toMatchSnapshot
();
// on componentDidMount
expect
(
props
.
actions
.
getProfiles
).
toHaveBeenCalledTimes
(
1
);
expect
(
props
.
actions
.
getProfiles
).
toBeCalledWith
(
0
,
100
);
expect
(
props
.
actions
.
getStatusesByIds
).
toHaveBeenCalledTimes
(
1
);
expect
(
props
.
actions
.
getStatusesByIds
).
toBeCalledWith
([
'
user_id_3
'
]);
// on componentWillReceiveProps
wrapper
.
setProps
({
statuses
:
{
user_id_1
:
'
online
'
,
user_id_2
:
'
away
'
,
user_id_3
:
'
offline
'
}});
expect
(
props
.
actions
.
getStatusesByIds
).
toHaveBeenCalledTimes
(
1
);
});
test
(
'
should call actions.getStatusesByIds on loadProfilesMissingStatus
'
,
()
=>
{
const
props
=
{...
baseProps
,
actions
:
{...
baseProps
.
actions
,
getStatusesByIds
:
jest
.
fn
()}};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
wrapper
.
instance
().
loadProfilesMissingStatus
(
props
.
users
,
props
.
statuses
);
expect
(
props
.
actions
.
getStatusesByIds
).
toHaveBeenCalledTimes
(
2
);
expect
(
props
.
actions
.
getStatusesByIds
).
toBeCalledWith
([
'
user_id_3
'
]);
props
.
statuses
=
{
user_id_1
:
'
online
'
,
user_id_2
:
'
away
'
,
user_id_3
:
'
offline
'
};
wrapper
.
instance
().
loadProfilesMissingStatus
(
props
.
users
,
props
.
statuses
);
expect
(
props
.
actions
.
getStatusesByIds
).
toHaveBeenCalledTimes
(
2
);
});
test
(
'
should call actions.setModalSearchTerm and match state on handleHide
'
,
()
=>
{
const
props
=
{...
baseProps
,
actions
:
{...
baseProps
.
actions
,
setModalSearchTerm
:
jest
.
fn
()}};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
wrapper
.
setState
({
show
:
true
});
wrapper
.
instance
().
handleHide
();
expect
(
props
.
actions
.
setModalSearchTerm
).
toHaveBeenCalledTimes
(
1
);
expect
(
props
.
actions
.
setModalSearchTerm
).
toBeCalledWith
(
''
);
expect
(
wrapper
.
state
(
'
show
'
)).
toEqual
(
false
);
});
test
(
'
should match state on setUsersLoadingState
'
,
()
=>
{
const
props
=
{...
baseProps
};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
wrapper
.
setState
({
loadingUsers
:
true
});
wrapper
.
instance
().
setUsersLoadingState
(
false
);
expect
(
wrapper
.
state
(
'
loadingUsers
'
)).
toEqual
(
false
);
wrapper
.
setState
({
loadingUsers
:
false
});
wrapper
.
instance
().
setUsersLoadingState
(
true
);
expect
(
wrapper
.
state
(
'
loadingUsers
'
)).
toEqual
(
true
);
});
test
(
'
should call on search
'
,
()
=>
{
const
props
=
{...
baseProps
,
actions
:
{...
baseProps
.
actions
,
setModalSearchTerm
:
jest
.
fn
()}};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
wrapper
.
instance
().
search
(
'
user_search
'
);
expect
(
props
.
actions
.
setModalSearchTerm
).
toHaveBeenCalledTimes
(
1
);
expect
(
props
.
actions
.
setModalSearchTerm
).
toBeCalledWith
(
'
user_search
'
);
});
test
(
'
should match state on handleDelete
'
,
()
=>
{
const
props
=
{...
baseProps
};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
wrapper
.
setState
({
values
:
[{
id
:
'
user_id_1
'
}]});
wrapper
.
instance
().
handleDelete
([{
id
:
'
user_id_2
'
}]);
expect
(
wrapper
.
state
(
'
values
'
)).
toEqual
([{
id
:
'
user_id_2
'
}]);
});
test
(
'
should match renderOption snapshot
'
,
()
=>
{
const
props
=
{...
baseProps
};
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
props
}
/>);
expect
(
wrapper
.
instance
().
renderOption
({
id
:
'
user_id_1
'
,
delete_at
:
0
},
true
,
jest
.
fn
())).
toMatchSnapshot
();
});
test
(
'
should match output on renderValue
'
,
()
=>
{
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
baseProps
}
/>);
expect
(
wrapper
.
instance
().
renderValue
({
id
:
'
user_id_2
'
,
username
:
'
username
'
})).
toEqual
(
'
username
'
);
});
test
(
'
should match output on handleSubmitImmediatelyOn
'
,
()
=>
{
const
wrapper
=
shallow
(<
MoreDirectChannels
{
...
baseProps
}
/>);
expect
(
wrapper
.
instance
().
handleSubmitImmediatelyOn
({
id
:
'
current_user_id
'
,
delete_at
:
0
})).
toEqual
(
true
);
expect
(
wrapper
.
instance
().
handleSubmitImmediatelyOn
({
id
:
'
user_id_2
'
,
delete_at
:
123
})).
toEqual
(
true
);
expect
(
wrapper
.
instance
().
handleSubmitImmediatelyOn
({
id
:
'
user_id_2
'
,
delete_at
:
0
})).
toEqual
(
false
);
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment