* MM-20758 MM-20762 Fix archived channels in more channels screen * Separate archived and public channels
This commit is contained in:
parent
7b0434dcf9
commit
49d9e5ef73
11 changed files with 99 additions and 68 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ exports[`ChannelMembers should match snapshot 1`] = `
|
|||
/>
|
||||
</View>
|
||||
<CustomList
|
||||
canRefresh={true}
|
||||
data={Array []}
|
||||
extraData={Object {}}
|
||||
isLandscape={false}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ exports[`MoreChannels should match snapshot 1`] = `
|
|||
</Text>
|
||||
</View>
|
||||
<CustomList
|
||||
canRefresh={false}
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ exports[`SelectTeam should match snapshot for teams 1`] = `
|
|||
/>
|
||||
</View>
|
||||
<CustomList
|
||||
canRefresh={true}
|
||||
data={Array []}
|
||||
extraData={false}
|
||||
isLandscape={false}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue