Automated cherry pick of #3635 (#3641)

* MM-20758 MM-20762 Fix archived channels in more channels screen

* Separate archived and public channels
This commit is contained in:
Mattermost Build 2019-12-02 10:52:14 +01:00 committed by Elias Nahum
parent 7b0434dcf9
commit 49d9e5ef73
11 changed files with 99 additions and 68 deletions

View file

@ -14,8 +14,6 @@ import {
leaveChannel as serviceLeaveChannel,
selectChannel,
getChannelStats,
getChannels,
getArchivedChannels,
} from 'mattermost-redux/actions/channels';
import {
getPosts,
@ -75,26 +73,6 @@ export function loadChannelsByTeamName(teamName) {
};
}
export function loadPublicAndArchivedChannels(teamId, publicPage, archivedPage, perPage, shouldLoadArchivedChannels) {
return async (dispatch) => {
return dispatch(getChannels(
teamId,
publicPage,
perPage
)).then(async (publicChannels) => {
if (shouldLoadArchivedChannels) {
const archivedChannels = await dispatch(getArchivedChannels(
teamId,
archivedPage,
perPage
));
return archivedChannels;
}
return publicChannels;
});
};
}
export function loadProfilesAndTeamMembersForDMSidebar(teamId) {
return async (dispatch, getState) => {
const state = getState();

View file

@ -31,16 +31,6 @@ exports[`CustomList should match snapshot with FlatList 1`] = `
onEndReachedThreshold={2}
onLayout={[Function]}
onScroll={[Function]}
refreshControl={
<RefreshControlMock
colors={
Array [
"#3d3c40",
]
}
tintColor="#3d3c40"
/>
}
removeClippedSubviews={true}
renderItem={[Function]}
scrollEventThrottle={60}

View file

@ -18,6 +18,7 @@ export default class CustomList extends PureComponent {
static propTypes = {
data: PropTypes.array.isRequired,
extraData: PropTypes.any,
canRefresh: PropTypes.bool,
listType: PropTypes.oneOf([FLATLIST, SECTIONLIST]),
loading: PropTypes.bool,
loadingComponent: PropTypes.element,
@ -35,10 +36,11 @@ export default class CustomList extends PureComponent {
};
static defaultProps = {
canRefresh: true,
isLandscape: false,
listType: FLATLIST,
showNoResults: true,
shouldRenderSeparator: true,
isLandscape: false,
};
constructor(props) {
@ -110,16 +112,19 @@ export default class CustomList extends PureComponent {
};
renderFlatList = () => {
const {data, extraData, theme, onRefresh, refreshing} = this.props;
const {canRefresh, data, extraData, theme, onRefresh, refreshing} = this.props;
const style = getStyleFromTheme(theme);
const refreshControl = (
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={[theme.centerChannelColor]}
tintColor={theme.centerChannelColor}
/>);
let refreshControl;
if (canRefresh) {
refreshControl = (
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={[theme.centerChannelColor]}
tintColor={theme.centerChannelColor}
/>);
}
return (
<FlatList

View file

@ -11,6 +11,7 @@ import CustomList, {FLATLIST, SECTIONLIST} from './index';
describe('CustomList', () => {
const baseProps = {
canRefresh: false,
data: [{username: 'username_1'}, {username: 'username_2'}],
listType: FLATLIST,
loading: false,

View file

@ -45,6 +45,7 @@ exports[`ChannelMembers should match snapshot 1`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
extraData={Object {}}
isLandscape={false}

View file

@ -73,6 +73,7 @@ exports[`MoreChannels should match snapshot 1`] = `
</Text>
</View>
<CustomList
canRefresh={false}
data={
Array [
Object {

View file

@ -6,7 +6,7 @@ import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import {isLandscape} from 'app/selectors/device';
import {General} from 'mattermost-redux/constants';
import {joinChannel, searchChannels} from 'mattermost-redux/actions/channels';
import {getArchivedChannels, getChannels, joinChannel, searchChannels} from 'mattermost-redux/actions/channels';
import {getChannelsInCurrentTeam, getMyChannelMemberships} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
@ -15,7 +15,7 @@ import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {handleSelectChannel, setChannelDisplayName, loadPublicAndArchivedChannels} from 'app/actions/views/channel';
import {handleSelectChannel, setChannelDisplayName} from 'app/actions/views/channel';
import MoreChannels from './more_channels';
@ -26,7 +26,7 @@ const joinablePublicChannels = createSelector(
getMyChannelMemberships,
(channels, myMembers) => {
return channels.filter((c) => {
return (!myMembers[c.id] && c.type === General.OPEN_CHANNEL);
return (!myMembers[c.id] && c.type === General.OPEN_CHANNEL && c.delete_at === 0);
});
}
);
@ -45,6 +45,8 @@ function mapStateToProps(state) {
const channels = joinablePublicChannels(state);
const archivedChannels = teamArchivedChannels(state);
const currentTeamId = getCurrentTeamId(state);
const canShowArchivedChannels = config.ExperimentalViewArchivedChannels === 'true' &&
isMinimumServerVersion(state.entities.general.serverVersion, 5, 18);
return {
canCreateChannels: showCreateOption(state, config, license, currentTeamId, General.OPEN_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
@ -54,16 +56,17 @@ function mapStateToProps(state) {
archivedChannels,
theme: getTheme(state),
isLandscape: isLandscape(state),
canShowArchivedChannels: isMinimumServerVersion(state.entities.general.serverVersion, 5, 18),
canShowArchivedChannels,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getArchivedChannels,
getChannels,
handleSelectChannel,
joinChannel,
loadPublicAndArchivedChannels,
searchChannels,
setChannelDisplayName,
}, dispatch),

View file

@ -21,7 +21,7 @@ import KeyboardLayout from 'app/components/layout/keyboard_layout';
import Loading from 'app/components/loading';
import SearchBar from 'app/components/search_bar';
import StatusBar from 'app/components/status_bar';
import {alertErrorWithFallback} from 'app/utils/general';
import {alertErrorWithFallback, emptyFunction} from 'app/utils/general';
import {goToScreen, dismissModal, setButtons} from 'app/actions/navigation';
import {
changeOpacity,
@ -33,9 +33,10 @@ import {
export default class MoreChannels extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
getArchivedChannels: PropTypes.func.isRequired,
getChannels: PropTypes.func.isRequired,
handleSelectChannel: PropTypes.func.isRequired,
joinChannel: PropTypes.func.isRequired,
loadPublicAndArchivedChannels: PropTypes.func.isRequired,
searchChannels: PropTypes.func.isRequired,
setChannelDisplayName: PropTypes.func.isRequired,
}).isRequired,
@ -65,7 +66,8 @@ export default class MoreChannels extends PureComponent {
this.searchTimeoutId = 0;
this.publicPage = -1;
this.archivedPage = -1;
this.next = true;
this.nextPublic = true;
this.nextArchived = true;
this.mounted = false;
this.state = {
@ -104,6 +106,7 @@ export default class MoreChannels extends PureComponent {
componentWillReceiveProps(nextProps) {
const {term} = this.state;
let channels;
let archivedChannels;
if (this.props.theme !== nextProps.theme) {
setNavigatorStyles(this.props.componentId, nextProps.theme);
@ -116,8 +119,24 @@ export default class MoreChannels extends PureComponent {
}
}
if (nextProps.archivedChannels !== this.props.archivedChannels) {
archivedChannels = nextProps.archivedChannels;
if (term) {
archivedChannels = this.filterChannels(nextProps.archivedChannels, term);
}
}
const nextState = {};
if (channels) {
this.setState({channels});
nextState.channels = channels;
}
if (archivedChannels) {
nextState.archivedChannels = archivedChannels;
}
if (nextState.archivedChannels || nextState.channels) {
this.setState(nextState);
}
}
@ -152,17 +171,30 @@ export default class MoreChannels extends PureComponent {
doGetChannels = () => {
const {actions, currentTeamId, canShowArchivedChannels} = this.props;
const {loading, term} = this.state;
const {loading, term, typeOfChannels} = this.state;
if (this.next && !loading && !term && this.mounted) {
if (!loading && !term && this.mounted) {
this.setState({loading: true}, () => {
actions.loadPublicAndArchivedChannels(
currentTeamId,
this.publicPage + 1,
this.archivedPage + 1,
General.CHANNELS_CHUNK_SIZE,
canShowArchivedChannels,
).then(this.loadedChannels);
switch (typeOfChannels) {
case 'public':
if (this.nextPublic) {
actions.getChannels(
currentTeamId,
this.publicPage + 1,
General.CHANNELS_CHUNK_SIZE,
).then(this.loadedChannels);
}
break;
case 'archived':
if (canShowArchivedChannels && this.nextArchived) {
actions.getArchivedChannels(
currentTeamId,
this.archivedPage + 1,
General.CHANNELS_CHUNK_SIZE,
).then(this.loadedChannels);
}
break;
}
});
}
};
@ -191,11 +223,17 @@ export default class MoreChannels extends PureComponent {
loadedChannels = ({data}) => {
if (this.mounted) {
if (data && !data.length) {
this.next = false;
const {typeOfChannels} = this.state;
const isPublic = typeOfChannels === 'public';
if (isPublic) {
this.publicPage += 1;
this.nextPublic = (data && !data.length);
} else {
this.archivedPage += 1;
this.nextArchived = (data && !data.length);
}
this.page += 1;
this.setState({loading: false});
}
};
@ -253,10 +291,12 @@ export default class MoreChannels extends PureComponent {
};
renderLoading = () => {
const {theme, channels} = this.props;
const {theme} = this.props;
const {typeOfChannels} = this.state;
const style = getStyleFromTheme(theme);
if (!channels.length && this.page <= 0) {
if ((typeOfChannels === 'public' && !this.nextPublic) ||
(typeOfChannels === 'archived' && !this.nextArchived)) {
return null;
}
@ -362,7 +402,10 @@ export default class MoreChannels extends PureComponent {
default:
typeOfChannels = this.state.typeOfChannels;
}
this.setState({typeOfChannels});
if (typeOfChannels !== this.state.typeOfChannels) {
this.setState({typeOfChannels, loading: false}, this.doGetChannels);
}
});
}
@ -370,7 +413,7 @@ export default class MoreChannels extends PureComponent {
const {formatMessage} = this.context.intl;
const {theme, isLandscape, canShowArchivedChannels} = this.props;
const {adding, channels, archivedChannels, loading, term, typeOfChannels} = this.state;
const more = term ? () => true : this.getChannels;
const more = term ? emptyFunction : this.getChannels;
const style = getStyleFromTheme(theme);
const publicChannelsText = formatMessage({id: 'more_channels.showPublicChannels', defaultMessage: 'Show: Public Channels'});
@ -440,6 +483,7 @@ export default class MoreChannels extends PureComponent {
</View>
{channelDropdown}
<CustomList
canRefresh={false}
data={activeChannels}
extraData={loading}
key='custom_list'

View file

@ -16,7 +16,8 @@ describe('MoreChannels', () => {
const actions = {
handleSelectChannel: jest.fn(),
joinChannel: jest.fn(),
loadPublicAndArchivedChannels: jest.fn().mockResolvedValue({data: [{id: 'id2', name: 'name2', display_name: 'display_name2'}]}),
getArchivedChannels: jest.fn().mockResolvedValue({data: [{id: 'id2', name: 'name2', display_name: 'display_name2', delete_at: 123}]}),
getChannels: jest.fn().mockResolvedValue({data: [{id: 'id', name: 'name', display_name: 'display_name'}]}),
searchChannels: jest.fn(),
setChannelDisplayName: jest.fn(),
};
@ -25,7 +26,7 @@ describe('MoreChannels', () => {
actions,
canCreateChannels: true,
channels: [{id: 'id', name: 'name', display_name: 'display_name'}],
archivedChannels: [{id: 'id2', name: 'archived', display_name: 'archived channel'}],
archivedChannels: [{id: 'id2', name: 'archived', display_name: 'archived channel', delete_at: 123}],
closeButton: {},
currentUserId: 'current_user_id',
currentTeamId: 'current_team_id',

View file

@ -91,6 +91,7 @@ exports[`SelectTeam should match snapshot for teams 1`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
extraData={false}
isLandscape={false}

View file

@ -52,6 +52,7 @@ exports[`SelectorScreen should match snapshot for channels 1`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
isLandscape={false}
listType="flat"
@ -148,6 +149,7 @@ exports[`SelectorScreen should match snapshot for channels 2`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
isLandscape={false}
listType="flat"
@ -244,6 +246,7 @@ exports[`SelectorScreen should match snapshot for explicit options 1`] = `
/>
</View>
<CustomList
canRefresh={true}
data={
Array [
Object {
@ -347,6 +350,7 @@ exports[`SelectorScreen should match snapshot for searching 1`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
isLandscape={false}
listType="flat"
@ -443,6 +447,7 @@ exports[`SelectorScreen should match snapshot for users 1`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
isLandscape={false}
listType="section"
@ -539,6 +544,7 @@ exports[`SelectorScreen should match snapshot for users 2`] = `
/>
</View>
<CustomList
canRefresh={true}
data={Array []}
isLandscape={false}
listType="section"