Fix types so the store can return undefined channels (#26393)
* Fix types so the store can return undefined channels * Address feedback * Revert gm change * Fix lint --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c22509eca2
Коммит
539daee634
@@ -86,7 +86,10 @@ export function executeCommand(message: string, args: CommandArgs): ActionFuncAs
|
|||||||
dispatch(GlobalActions.sendEphemeralPost('/leave is not supported in reply threads. Use it in the center channel instead.', args.channel_id, args.root_id));
|
dispatch(GlobalActions.sendEphemeralPost('/leave is not supported in reply threads. Use it in the center channel instead.', args.channel_id, args.root_id));
|
||||||
return {data: true};
|
return {data: true};
|
||||||
}
|
}
|
||||||
const channel = getCurrentChannel(state) || {};
|
const channel = getCurrentChannel(state);
|
||||||
|
if (!channel) {
|
||||||
|
return {data: false};
|
||||||
|
}
|
||||||
if (channel.type === Constants.PRIVATE_CHANNEL) {
|
if (channel.type === Constants.PRIVATE_CHANNEL) {
|
||||||
dispatch(openModal({modalId: ModalIdentifiers.LEAVE_PRIVATE_CHANNEL_MODAL, dialogType: LeaveChannelModal, dialogProps: {channel}}));
|
dispatch(openModal({modalId: ModalIdentifiers.LEAVE_PRIVATE_CHANNEL_MODAL, dialogType: LeaveChannelModal, dialogProps: {channel}}));
|
||||||
return {data: true};
|
return {data: true};
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ export function setEditingPost(postId = '', refocusId = '', title = '', isRHS =
|
|||||||
const license = state.entities.general.license;
|
const license = state.entities.general.license;
|
||||||
const userId = getCurrentUserId(state);
|
const userId = getCurrentUserId(state);
|
||||||
const channel = getChannel(state, post.channel_id);
|
const channel = getChannel(state, post.channel_id);
|
||||||
const teamId = channel.team_id || '';
|
const teamId = channel?.team_id || '';
|
||||||
|
|
||||||
const canEditNow = canEditPost(state, config, license, teamId, post.channel_id, userId, post);
|
const canEditNow = canEditPost(state, config, license, teamId, post.channel_id, userId, post);
|
||||||
|
|
||||||
|
|||||||
@@ -64,14 +64,14 @@ import type {GlobalState} from 'types/store';
|
|||||||
export function goToLastViewedChannel(): ActionFuncAsync {
|
export function goToLastViewedChannel(): ActionFuncAsync {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const currentChannel = getCurrentChannel(state) || {};
|
const currentChannel = getCurrentChannel(state);
|
||||||
const channelsInTeam = getChannelsNameMapInCurrentTeam(state);
|
const channelsInTeam = getChannelsNameMapInCurrentTeam(state);
|
||||||
const directChannel = getAllDirectChannelsNameMapInCurrentTeam(state);
|
const directChannel = getAllDirectChannelsNameMapInCurrentTeam(state);
|
||||||
const channels = Object.assign({}, channelsInTeam, directChannel);
|
const channels = Object.assign({}, channelsInTeam, directChannel);
|
||||||
|
|
||||||
let channelToSwitchTo = getChannelByName(channels, getLastViewedChannelName(state));
|
let channelToSwitchTo = getChannelByName(channels, getLastViewedChannelName(state));
|
||||||
|
|
||||||
if (currentChannel.id === channelToSwitchTo!.id) {
|
if (currentChannel?.id === channelToSwitchTo!.id) {
|
||||||
channelToSwitchTo = getChannelByName(channels, getRedirectChannelNameForTeam(state, getCurrentTeamId(state)));
|
channelToSwitchTo = getChannelByName(channels, getRedirectChannelNameForTeam(state, getCurrentTeamId(state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,10 @@ export function switchToChannelById(channelId: string): ActionFuncAsync {
|
|||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const channel = getChannel(state, channelId);
|
const channel = getChannel(state, channelId);
|
||||||
return dispatch(switchToChannel(channel));
|
if (channel) {
|
||||||
|
return dispatch(switchToChannel(channel));
|
||||||
|
}
|
||||||
|
return {data: true};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +122,9 @@ export function switchToChannel(channel: Channel & {userId?: string}): ActionFun
|
|||||||
getHistory().push(`${teamUrl}/messages/@${channel.name}`);
|
getHistory().push(`${teamUrl}/messages/@${channel.name}`);
|
||||||
} else if (channel.type === Constants.GM_CHANNEL) {
|
} else if (channel.type === Constants.GM_CHANNEL) {
|
||||||
const gmChannel = getChannel(state, channel.id);
|
const gmChannel = getChannel(state, channel.id);
|
||||||
|
if (!gmChannel?.name) {
|
||||||
|
return {error: true};
|
||||||
|
}
|
||||||
getHistory().push(`${teamUrl}/channels/${gmChannel.name}`);
|
getHistory().push(`${teamUrl}/channels/${gmChannel.name}`);
|
||||||
} else if (channel.type === Constants.THREADS) {
|
} else if (channel.type === Constants.THREADS) {
|
||||||
getHistory().push(`${teamUrl}/${channel.name}`);
|
getHistory().push(`${teamUrl}/${channel.name}`);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import SaveChangesPanel from '../../save_changes_panel';
|
|||||||
|
|
||||||
export interface ChannelDetailsProps {
|
export interface ChannelDetailsProps {
|
||||||
channelID: string;
|
channelID: string;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
team?: Team;
|
team?: Team;
|
||||||
groups: Group[];
|
groups: Group[];
|
||||||
totalGroups: number;
|
totalGroups: number;
|
||||||
@@ -108,9 +108,9 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
constructor(props: ChannelDetailsProps) {
|
constructor(props: ChannelDetailsProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isSynced: Boolean(props.channel.group_constrained),
|
isSynced: Boolean(props.channel?.group_constrained),
|
||||||
isPublic: props.channel.type === Constants.OPEN_CHANNEL,
|
isPublic: props.channel?.type === Constants.OPEN_CHANNEL,
|
||||||
isDefault: props.channel.name === Constants.DEFAULT_CHANNEL,
|
isDefault: props.channel?.name === Constants.DEFAULT_CHANNEL,
|
||||||
isPrivacyChanging: false,
|
isPrivacyChanging: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
totalGroups: props.totalGroups,
|
totalGroups: props.totalGroups,
|
||||||
@@ -127,25 +127,25 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
previousServerError: undefined,
|
previousServerError: undefined,
|
||||||
channelPermissions: props.channelPermissions,
|
channelPermissions: props.channelPermissions,
|
||||||
teamScheme: props.teamScheme,
|
teamScheme: props.teamScheme,
|
||||||
isLocalArchived: props.channel.delete_at > 0,
|
isLocalArchived: props.channel?.delete_at !== 0,
|
||||||
showArchiveConfirmModal: false,
|
showArchiveConfirmModal: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: ChannelDetailsProps) {
|
componentDidUpdate(prevProps: ChannelDetailsProps) {
|
||||||
const {channel, totalGroups, actions} = this.props;
|
const {channel, totalGroups, actions} = this.props;
|
||||||
if (channel.id !== prevProps.channel.id || totalGroups !== prevProps.totalGroups) {
|
if (channel?.id !== prevProps.channel?.id || totalGroups !== prevProps.totalGroups) {
|
||||||
this.setState({
|
this.setState({
|
||||||
totalGroups,
|
totalGroups,
|
||||||
isSynced: Boolean(channel.group_constrained),
|
isSynced: Boolean(channel?.group_constrained),
|
||||||
isPublic: channel.type === Constants.OPEN_CHANNEL,
|
isPublic: channel?.type === Constants.OPEN_CHANNEL,
|
||||||
isDefault: channel.name === Constants.DEFAULT_CHANNEL,
|
isDefault: channel?.name === Constants.DEFAULT_CHANNEL,
|
||||||
isLocalArchived: channel.delete_at > 0,
|
isLocalArchived: channel?.delete_at !== 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have the team and channel on mount, we need to request the team after we load the channel
|
// If we don't have the team and channel on mount, we need to request the team after we load the channel
|
||||||
if (!prevProps.team?.id && !prevProps.channel.team_id && channel.team_id) {
|
if (!prevProps.team?.id && !prevProps.channel?.team_id && channel?.team_id) {
|
||||||
actions.getTeam(channel.team_id).
|
actions.getTeam(channel.team_id).
|
||||||
then(async (data: any) => {
|
then(async (data: any) => {
|
||||||
if (data.data && data.data.scheme_id) {
|
if (data.data && data.data.scheme_id) {
|
||||||
@@ -167,7 +167,7 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
actions.getChannel(channelID);
|
actions.getChannel(channelID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel.team_id) {
|
if (channel?.team_id) {
|
||||||
actions.getTeam(channel.team_id).
|
actions.getTeam(channel.team_id).
|
||||||
then(async (data: any) => {
|
then(async (data: any) => {
|
||||||
if (data.data && data.data.scheme_id) {
|
if (data.data && data.data.scheme_id) {
|
||||||
@@ -206,7 +206,7 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
|
|
||||||
private setToggles = (isSynced: boolean, isPublic: boolean) => {
|
private setToggles = (isSynced: boolean, isPublic: boolean) => {
|
||||||
const {channel} = this.props;
|
const {channel} = this.props;
|
||||||
const isOriginallyPublic = channel.type === Constants.OPEN_CHANNEL;
|
const isOriginallyPublic = channel?.type === Constants.OPEN_CHANNEL;
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
saveNeeded: true,
|
saveNeeded: true,
|
||||||
@@ -355,7 +355,7 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
this.setState({showArchiveConfirmModal: true});
|
this.setState({showArchiveConfirmModal: true});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const isOriginallyPublic = channel.type === Constants.OPEN_CHANNEL;
|
const isOriginallyPublic = channel?.type === Constants.OPEN_CHANNEL;
|
||||||
if (isSynced) {
|
if (isSynced) {
|
||||||
isPublic = false;
|
isPublic = false;
|
||||||
isPrivacyChanging = isOriginallyPublic;
|
isPrivacyChanging = isOriginallyPublic;
|
||||||
@@ -380,11 +380,16 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
};
|
};
|
||||||
|
|
||||||
private handleSubmit = async () => {
|
private handleSubmit = async () => {
|
||||||
|
const {groups: origGroups, channelID, actions, channel} = this.props;
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({showConvertConfirmModal: false, showRemoveConfirmModal: false, showConvertAndRemoveConfirmModal: false, showArchiveConfirmModal: false, saving: true});
|
this.setState({showConvertConfirmModal: false, showRemoveConfirmModal: false, showConvertAndRemoveConfirmModal: false, showArchiveConfirmModal: false, saving: true});
|
||||||
const {groups, isSynced, isPublic, isPrivacyChanging, channelPermissions, usersToAdd, usersToRemove, rolesToUpdate} = this.state;
|
const {groups, isSynced, isPublic, isPrivacyChanging, channelPermissions, usersToAdd, usersToRemove, rolesToUpdate} = this.state;
|
||||||
let serverError: JSX.Element | undefined;
|
let serverError: JSX.Element | undefined;
|
||||||
let saveNeeded = false;
|
let saveNeeded = false;
|
||||||
const {groups: origGroups, channelID, actions, channel} = this.props;
|
|
||||||
|
|
||||||
if (this.channelToBeArchived()) {
|
if (this.channelToBeArchived()) {
|
||||||
const result = await actions.deleteChannel(channel.id);
|
const result = await actions.deleteChannel(channel.id);
|
||||||
@@ -607,13 +612,13 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
|
|
||||||
private channelToBeArchived = (): boolean => {
|
private channelToBeArchived = (): boolean => {
|
||||||
const {isLocalArchived} = this.state;
|
const {isLocalArchived} = this.state;
|
||||||
const isServerArchived = this.props.channel.delete_at !== 0;
|
const isServerArchived = this.props.channel?.delete_at !== 0;
|
||||||
return isLocalArchived && !isServerArchived;
|
return isLocalArchived && !isServerArchived;
|
||||||
};
|
};
|
||||||
|
|
||||||
private channelToBeRestored = (): boolean => {
|
private channelToBeRestored = (): boolean => {
|
||||||
const {isLocalArchived} = this.state;
|
const {isLocalArchived} = this.state;
|
||||||
const isServerArchived = this.props.channel.delete_at !== 0;
|
const isServerArchived = this.props.channel?.delete_at !== 0;
|
||||||
return !isLocalArchived && isServerArchived;
|
return !isLocalArchived && isServerArchived;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -681,7 +686,7 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
this.setState(newState);
|
this.setState(newState);
|
||||||
};
|
};
|
||||||
|
|
||||||
public render = (): JSX.Element => {
|
public render = () => {
|
||||||
const {
|
const {
|
||||||
totalGroups,
|
totalGroups,
|
||||||
saving,
|
saving,
|
||||||
@@ -703,6 +708,11 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
showArchiveConfirmModal,
|
showArchiveConfirmModal,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const {channel, team} = this.props;
|
const {channel, team} = this.props;
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const missingGroup = (og: {id: string}) => !groups.find((g: Group) => g.id === og.id);
|
const missingGroup = (og: {id: string}) => !groups.find((g: Group) => g.id === og.id);
|
||||||
const removedGroups = this.props.groups.filter(missingGroup);
|
const removedGroups = this.props.groups.filter(missingGroup);
|
||||||
const nonArchivedContent = (
|
const nonArchivedContent = (
|
||||||
@@ -722,7 +732,7 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
|
|||||||
teamSchemeID={teamScheme?.id}
|
teamSchemeID={teamScheme?.id}
|
||||||
teamSchemeDisplayName={teamScheme?.display_name}
|
teamSchemeDisplayName={teamScheme?.display_name}
|
||||||
guestAccountsEnabled={this.props.guestAccountsEnabled}
|
guestAccountsEnabled={this.props.guestAccountsEnabled}
|
||||||
isPublic={this.props.channel.type === Constants.OPEN_CHANNEL}
|
isPublic={channel.type === Constants.OPEN_CHANNEL}
|
||||||
readOnly={this.props.isDisabled}
|
readOnly={this.props.isDisabled}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import Constants, {ModalIdentifiers} from 'utils/constants';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
filters: GetFilteredUsersStatsOpts;
|
filters: GetFilteredUsersStatsOpts;
|
||||||
|
|
||||||
users: UserProfile[];
|
users: UserProfile[];
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function makeMapStateToProps() {
|
|||||||
|
|
||||||
const config = getConfig(state);
|
const config = getConfig(state);
|
||||||
const channelMembers = getChannelMembersInChannels(state)[channelId] || {};
|
const channelMembers = getChannelMembersInChannels(state)[channelId] || {};
|
||||||
const channel = getChannel(state, channelId) || {channel_id: channelId};
|
const channel = getChannel(state, channelId);
|
||||||
const searchTerm = state.views.search.userGridSearch?.term || '';
|
const searchTerm = state.views.search.userGridSearch?.term || '';
|
||||||
const filters = getUserGridFilters(state);
|
const filters = getUserGridFilters(state);
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||||||
|
|
||||||
const guestAccountsEnabled = config.EnableGuestAccounts === 'true';
|
const guestAccountsEnabled = config.EnableGuestAccounts === 'true';
|
||||||
const channelID = ownProps.match.params.channel_id;
|
const channelID = ownProps.match.params.channel_id;
|
||||||
const channel = getChannel(state, channelID) || {};
|
const channel = getChannel(state, channelID);
|
||||||
const team = getTeam(state, channel.team_id);
|
const team = channel ? getTeam(state, channel.team_id) : undefined;
|
||||||
const groups = getGroupsAssociatedToChannel(state, channelID);
|
const groups = getGroupsAssociatedToChannel(state, channelID);
|
||||||
const totalGroups = groups.length;
|
const totalGroups = groups.length;
|
||||||
const allGroups = getAllGroups(state);
|
const allGroups = getAllGroups(state);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export type Props = {
|
|||||||
currentChannelMembersCount: number;
|
currentChannelMembersCount: number;
|
||||||
|
|
||||||
// Data used in multiple places of the component
|
// Data used in multiple places of the component
|
||||||
currentChannel: Channel;
|
currentChannel?: Channel;
|
||||||
|
|
||||||
//Data used for DM prewritten messages
|
//Data used for DM prewritten messages
|
||||||
currentChannelTeammateUsername?: string;
|
currentChannelTeammateUsername?: string;
|
||||||
@@ -239,7 +239,7 @@ type State = {
|
|||||||
uploadsProgressPercent: {[clientID: string]: FilePreviewInfo};
|
uploadsProgressPercent: {[clientID: string]: FilePreviewInfo};
|
||||||
renderScrollbar: boolean;
|
renderScrollbar: boolean;
|
||||||
scrollbarWidth: number;
|
scrollbarWidth: number;
|
||||||
currentChannel: Channel;
|
currentChannel?: Channel;
|
||||||
errorClass: string | null;
|
errorClass: string | null;
|
||||||
serverError: (ServerError & {submittedMessage?: string}) | null;
|
serverError: (ServerError & {submittedMessage?: string}) | null;
|
||||||
postError?: React.ReactNode;
|
postError?: React.ReactNode;
|
||||||
@@ -271,7 +271,7 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
currentChannel: props.currentChannel,
|
currentChannel: props.currentChannel,
|
||||||
};
|
};
|
||||||
if (
|
if (
|
||||||
props.currentChannel.id !== state.currentChannel.id ||
|
props.currentChannel?.id !== state.currentChannel?.id ||
|
||||||
(props.isRemoteDraft && props.draft.message !== state.message)
|
(props.isRemoteDraft && props.draft.message !== state.message)
|
||||||
) {
|
) {
|
||||||
updatedState = {
|
updatedState = {
|
||||||
@@ -321,14 +321,14 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||||
const {currentChannel, actions} = this.props;
|
const {currentChannel, actions} = this.props;
|
||||||
if (prevProps.currentChannel.id !== currentChannel.id) {
|
if (prevProps.currentChannel?.id !== currentChannel?.id) {
|
||||||
this.lastChannelSwitchAt = Date.now();
|
this.lastChannelSwitchAt = Date.now();
|
||||||
this.focusTextbox();
|
this.focusTextbox();
|
||||||
this.saveDraftWithShow(prevProps);
|
this.saveDraftWithShow(prevProps);
|
||||||
this.getChannelMemberCountsByGroup();
|
this.getChannelMemberCountsByGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentChannel.id !== prevProps.currentChannel.id) {
|
if (currentChannel?.id !== prevProps.currentChannel?.id) {
|
||||||
actions.setShowPreview(false);
|
actions.setShowPreview(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +356,7 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
getChannelMemberCountsByGroup = () => {
|
getChannelMemberCountsByGroup = () => {
|
||||||
const {useLDAPGroupMentions, useCustomGroupMentions, currentChannel, actions, draft} = this.props;
|
const {useLDAPGroupMentions, useCustomGroupMentions, currentChannel, actions, draft} = this.props;
|
||||||
|
|
||||||
if ((useLDAPGroupMentions || useCustomGroupMentions) && currentChannel.id) {
|
if ((useLDAPGroupMentions || useCustomGroupMentions) && currentChannel?.id) {
|
||||||
const mentions = mentionsMinusSpecialMentionsInText(draft.message);
|
const mentions = mentionsMinusSpecialMentionsInText(draft.message);
|
||||||
|
|
||||||
if (mentions.length === 1) {
|
if (mentions.length === 1) {
|
||||||
@@ -458,7 +458,11 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
doSubmit = async (e?: React.FormEvent) => {
|
doSubmit = async (e?: React.FormEvent) => {
|
||||||
const channelId = this.props.currentChannel.id;
|
const channelId = this.props.currentChannel?.id;
|
||||||
|
if (!channelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@@ -628,6 +632,10 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
useCustomGroupMentions,
|
useCustomGroupMentions,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
if (!updateChannel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.setShowPreview(false);
|
this.setShowPreview(false);
|
||||||
this.isDraftSubmitting = true;
|
this.isDraftSubmitting = true;
|
||||||
|
|
||||||
@@ -671,7 +679,7 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data} = await this.props.actions.getChannelTimezones(this.props.currentChannel.id);
|
const {data} = await this.props.actions.getChannelTimezones(updateChannel.id);
|
||||||
channelTimezoneCount = data ? data.length : 0;
|
channelTimezoneCount = data ? data.length : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,6 +756,10 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
useCustomGroupMentions,
|
useCustomGroupMentions,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
if (!currentChannel) {
|
||||||
|
return {data: false};
|
||||||
|
}
|
||||||
|
|
||||||
let post = originalPost;
|
let post = originalPost;
|
||||||
|
|
||||||
post.channel_id = currentChannel.id;
|
post.channel_id = currentChannel.id;
|
||||||
@@ -864,8 +876,10 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
emitTypingEvent = () => {
|
emitTypingEvent = () => {
|
||||||
const channelId = this.props.currentChannel.id;
|
const channelId = this.props.currentChannel?.id;
|
||||||
GlobalActions.emitLocalUserTypingEvent(channelId, '');
|
if (channelId) {
|
||||||
|
GlobalActions.emitLocalUserTypingEvent(channelId, '');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (e: React.ChangeEvent<TextboxElement>) => {
|
handleChange = (e: React.ChangeEvent<TextboxElement>) => {
|
||||||
@@ -889,11 +903,15 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
this.handleDraftChange(draft);
|
this.handleDraftChange(draft);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleDraftChange = (draft: PostDraft, channelId = this.props.currentChannel.id, instant = false) => {
|
handleDraftChange = (draft: PostDraft, channelId = this.props.currentChannel?.id, instant = false) => {
|
||||||
if (this.saveDraftFrame) {
|
if (this.saveDraftFrame) {
|
||||||
clearTimeout(this.saveDraftFrame);
|
clearTimeout(this.saveDraftFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!channelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (instant) {
|
if (instant) {
|
||||||
this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, draft, channelId);
|
this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, draft, channelId);
|
||||||
} else {
|
} else {
|
||||||
@@ -905,7 +923,10 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
this.draftsForChannel[channelId] = draft;
|
this.draftsForChannel[channelId] = draft;
|
||||||
};
|
};
|
||||||
|
|
||||||
removeDraft = (channelId = this.props.currentChannel.id) => {
|
removeDraft = (channelId = this.props.currentChannel?.id) => {
|
||||||
|
if (!channelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, null, channelId);
|
this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, null, channelId);
|
||||||
this.draftsForChannel[channelId] = null;
|
this.draftsForChannel[channelId] = null;
|
||||||
};
|
};
|
||||||
@@ -986,6 +1007,9 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
removePreview = (id: string) => {
|
removePreview = (id: string) => {
|
||||||
|
if (!this.props.currentChannel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let modifiedDraft = {} as PostDraft;
|
let modifiedDraft = {} as PostDraft;
|
||||||
const draft = {...this.props.draft};
|
const draft = {...this.props.draft};
|
||||||
|
|
||||||
@@ -1264,6 +1288,9 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handlePostPriorityApply = (settings?: PostPriorityMetadata) => {
|
handlePostPriorityApply = (settings?: PostPriorityMetadata) => {
|
||||||
|
if (!this.props.currentChannel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const updatedDraft = {
|
const updatedDraft = {
|
||||||
...this.props.draft,
|
...this.props.draft,
|
||||||
};
|
};
|
||||||
@@ -1309,7 +1336,7 @@ class AdvancedCreatePost extends React.PureComponent<Props, State> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentChannel.type === Constants.DM_CHANNEL) {
|
if (currentChannel?.type === Constants.DM_CHANNEL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ function makeMapStateToProps() {
|
|||||||
return (state: GlobalState) => {
|
return (state: GlobalState) => {
|
||||||
const config = getConfig(state);
|
const config = getConfig(state);
|
||||||
const license = getLicense(state);
|
const license = getLicense(state);
|
||||||
const currentChannel = getCurrentChannel(state) || {};
|
const currentChannel = getCurrentChannel(state);
|
||||||
const currentChannelTeammateUsername = getUser(state, currentChannel.teammate_id || '')?.username;
|
const currentChannelTeammateUsername = currentChannel ? getUser(state, currentChannel.teammate_id || '')?.username : undefined;
|
||||||
const draft = getChannelDraft(state, currentChannel.id);
|
const draft = getChannelDraft(state, currentChannel?.id || '');
|
||||||
const isRemoteDraft = state.views.drafts.remotes[`${StoragePrefixes.DRAFT}${currentChannel.id}`] || false;
|
const isRemoteDraft = (currentChannel && state.views.drafts.remotes[`${StoragePrefixes.DRAFT}${currentChannel.id}`]) || false;
|
||||||
const latestReplyablePostId = getLatestReplyablePostId(state);
|
const latestReplyablePostId = getLatestReplyablePostId(state);
|
||||||
const currentChannelMembersCount = getCurrentChannelStats(state) ? getCurrentChannelStats(state).member_count : 1;
|
const currentChannelMembersCount = getCurrentChannelStats(state)?.member_count ?? 1;
|
||||||
const enableEmojiPicker = config.EnableEmojiPicker === 'true';
|
const enableEmojiPicker = config.EnableEmojiPicker === 'true';
|
||||||
const enableGifPicker = config.EnableGifPicker === 'true';
|
const enableGifPicker = config.EnableGifPicker === 'true';
|
||||||
const enableConfirmNotificationsToChannel = config.EnableConfirmNotificationsToChannel === 'true';
|
const enableConfirmNotificationsToChannel = config.EnableConfirmNotificationsToChannel === 'true';
|
||||||
@@ -82,9 +82,11 @@ function makeMapStateToProps() {
|
|||||||
const isLDAPEnabled = license?.IsLicensed === 'true' && license?.LDAPGroups === 'true';
|
const isLDAPEnabled = license?.IsLicensed === 'true' && license?.LDAPGroups === 'true';
|
||||||
const useCustomGroupMentions = isCustomGroupsEnabled(state) && haveICurrentChannelPermission(state, Permissions.USE_GROUP_MENTIONS);
|
const useCustomGroupMentions = isCustomGroupsEnabled(state) && haveICurrentChannelPermission(state, Permissions.USE_GROUP_MENTIONS);
|
||||||
const useLDAPGroupMentions = isLDAPEnabled && haveICurrentChannelPermission(state, Permissions.USE_GROUP_MENTIONS);
|
const useLDAPGroupMentions = isLDAPEnabled && haveICurrentChannelPermission(state, Permissions.USE_GROUP_MENTIONS);
|
||||||
const channelMemberCountsByGroup = selectChannelMemberCountsByGroup(state, currentChannel.id);
|
const channelMemberCountsByGroup = currentChannel ? selectChannelMemberCountsByGroup(state, currentChannel.id) : {};
|
||||||
const currentTeamId = getCurrentTeamId(state);
|
const currentTeamId = getCurrentTeamId(state);
|
||||||
const groupsWithAllowReference = useLDAPGroupMentions || useCustomGroupMentions ? getAssociatedGroupsForReferenceByMention(state, currentTeamId, currentChannel.id) : null;
|
const groupsWithAllowReference = (currentChannel && (useLDAPGroupMentions || useCustomGroupMentions)) ?
|
||||||
|
getAssociatedGroupsForReferenceByMention(state, currentTeamId, currentChannel.id) :
|
||||||
|
null;
|
||||||
const enableTutorial = config.EnableTutorial === 'true';
|
const enableTutorial = config.EnableTutorial === 'true';
|
||||||
const tutorialStep = getInt(state, TutorialTourName.ONBOARDING_TUTORIAL_STEP, currentUserId, 0);
|
const tutorialStep = getInt(state, TutorialTourName.ONBOARDING_TUTORIAL_STEP, currentUserId, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,10 @@ function NotificationFromMembersModal(props: Props) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const modalTitle = formatMessage({id: 'postypes.custom_open_pricing_modal_post_renderer.membersThatRequested', defaultMessage: 'Members that requested '});
|
const modalTitle = formatMessage({id: 'postypes.custom_open_pricing_modal_post_renderer.membersThatRequested', defaultMessage: 'Members that requested '});
|
||||||
|
|
||||||
const modalHeaderText = (
|
const modalHeaderText = (
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const popoverMarkdownOptions = {singleline: false, mentionHighlight: false, atMe
|
|||||||
export type Props = {
|
export type Props = {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
currentUser: UserProfile;
|
currentUser: UserProfile;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
memberCount?: number;
|
memberCount?: number;
|
||||||
channelMember?: ChannelMembership;
|
channelMember?: ChannelMembership;
|
||||||
dmUser?: UserProfile;
|
dmUser?: UserProfile;
|
||||||
@@ -169,7 +169,7 @@ class ChannelHeader extends React.PureComponent<Props, State> {
|
|||||||
showChannelFiles = () => {
|
showChannelFiles = () => {
|
||||||
if (this.props.rhsState === RHSStates.CHANNEL_FILES) {
|
if (this.props.rhsState === RHSStates.CHANNEL_FILES) {
|
||||||
this.props.actions.closeRightHandSide();
|
this.props.actions.closeRightHandSide();
|
||||||
} else {
|
} else if (this.props.channel) {
|
||||||
this.props.actions.showChannelFiles(this.props.channel.id);
|
this.props.actions.showChannelFiles(this.props.channel.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -180,6 +180,10 @@ class ChannelHeader extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {actions, channel} = this.props;
|
const {actions, channel} = this.props;
|
||||||
|
if (!channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const modalData = {
|
const modalData = {
|
||||||
modalId: ModalIdentifiers.EDIT_CHANNEL_HEADER,
|
modalId: ModalIdentifiers.EDIT_CHANNEL_HEADER,
|
||||||
dialogType: EditChannelHeaderModal,
|
dialogType: EditChannelHeaderModal,
|
||||||
@@ -212,7 +216,7 @@ class ChannelHeader extends React.PureComponent<Props, State> {
|
|||||||
toggleChannelMembersRHS = () => {
|
toggleChannelMembersRHS = () => {
|
||||||
if (this.props.rhsState === RHSStates.CHANNEL_MEMBERS) {
|
if (this.props.rhsState === RHSStates.CHANNEL_MEMBERS) {
|
||||||
this.props.actions.closeRightHandSide();
|
this.props.actions.closeRightHandSide();
|
||||||
} else {
|
} else if (this.props.channel) {
|
||||||
this.props.actions.showChannelMembers(this.props.channel.id);
|
this.props.actions.showChannelMembers(this.props.channel.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -259,6 +263,10 @@ class ChannelHeader extends React.PureComponent<Props, State> {
|
|||||||
hasGuests,
|
hasGuests,
|
||||||
hideGuestTags,
|
hideGuestTags,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const {formatMessage} = this.props.intl;
|
const {formatMessage} = this.props.intl;
|
||||||
const ariaLabelChannelHeader = this.props.intl.formatMessage({id: 'accessibility.sections.channelHeader', defaultMessage: 'channel header region'});
|
const ariaLabelChannelHeader = this.props.intl.formatMessage({id: 'accessibility.sections.channelHeader', defaultMessage: 'channel header region'});
|
||||||
|
|
||||||
|
|||||||
@@ -19,17 +19,20 @@ const ChannelHeaderTitleFavorite = () => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const isFavorite = useSelector(isCurrentChannelFavorite);
|
const isFavorite = useSelector(isCurrentChannelFavorite);
|
||||||
const channel = useSelector(getCurrentChannel);
|
const channel = useSelector(getCurrentChannel);
|
||||||
const channelIsArchived = channel.delete_at !== 0;
|
const channelIsArchived = (channel?.delete_at ?? 0) > 0;
|
||||||
const toggleFavoriteRef = useRef<HTMLButtonElement>(null);
|
const toggleFavoriteRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
const toggleFavoriteCallback = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
const toggleFavoriteCallback = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
if (!channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isFavorite) {
|
if (isFavorite) {
|
||||||
dispatch(unfavoriteChannel(channel.id));
|
dispatch(unfavoriteChannel(channel.id));
|
||||||
} else {
|
} else {
|
||||||
dispatch(favoriteChannel(channel.id));
|
dispatch(favoriteChannel(channel.id));
|
||||||
}
|
}
|
||||||
}, [isFavorite, channel.id]);
|
}, [isFavorite, channel?.id]);
|
||||||
|
|
||||||
const removeTooltipLink = useCallback(() => {
|
const removeTooltipLink = useCallback(() => {
|
||||||
// Bootstrap adds the attr dynamically, removing it to prevent a11y readout
|
// Bootstrap adds the attr dynamically, removing it to prevent a11y readout
|
||||||
|
|||||||
@@ -49,16 +49,13 @@ import type {GlobalState} from 'types/store';
|
|||||||
|
|
||||||
import ChannelHeader from './channel_header';
|
import ChannelHeader from './channel_header';
|
||||||
|
|
||||||
const EMPTY_CHANNEL = {};
|
|
||||||
const EMPTY_CHANNEL_STATS = {member_count: 0, guest_count: 0, pinnedpost_count: 0, files_count: 0};
|
|
||||||
|
|
||||||
function makeMapStateToProps() {
|
function makeMapStateToProps() {
|
||||||
const doGetProfilesInChannel = makeGetProfilesInChannel();
|
const doGetProfilesInChannel = makeGetProfilesInChannel();
|
||||||
const getCustomStatus = makeGetCustomStatus();
|
const getCustomStatus = makeGetCustomStatus();
|
||||||
let timestampUnits: string[] = [];
|
let timestampUnits: string[] = [];
|
||||||
|
|
||||||
return function mapStateToProps(state: GlobalState) {
|
return function mapStateToProps(state: GlobalState) {
|
||||||
const channel = getCurrentChannel(state) || EMPTY_CHANNEL;
|
const channel = getCurrentChannel(state);
|
||||||
const user = getCurrentUser(state);
|
const user = getCurrentUser(state);
|
||||||
const teams = getMyTeams(state);
|
const teams = getMyTeams(state);
|
||||||
const hasMoreThanOneTeam = teams.length > 1;
|
const hasMoreThanOneTeam = teams.length > 1;
|
||||||
@@ -77,7 +74,7 @@ function makeMapStateToProps() {
|
|||||||
} else if (channel && channel.type === General.GM_CHANNEL) {
|
} else if (channel && channel.type === General.GM_CHANNEL) {
|
||||||
gmMembers = doGetProfilesInChannel(state, channel.id);
|
gmMembers = doGetProfilesInChannel(state, channel.id);
|
||||||
}
|
}
|
||||||
const stats = getCurrentChannelStats(state) || EMPTY_CHANNEL_STATS;
|
const stats = getCurrentChannelStats(state);
|
||||||
|
|
||||||
let isLastActiveEnabled = false;
|
let isLastActiveEnabled = false;
|
||||||
if (dmUser) {
|
if (dmUser) {
|
||||||
@@ -89,7 +86,7 @@ function makeMapStateToProps() {
|
|||||||
teamId: getCurrentTeamId(state),
|
teamId: getCurrentTeamId(state),
|
||||||
channel,
|
channel,
|
||||||
channelMember: getMyCurrentChannelMembership(state),
|
channelMember: getMyCurrentChannelMembership(state),
|
||||||
memberCount: stats.member_count,
|
memberCount: stats?.member_count || 0,
|
||||||
currentUser: user,
|
currentUser: user,
|
||||||
dmUser,
|
dmUser,
|
||||||
gmMembers,
|
gmMembers,
|
||||||
@@ -98,8 +95,8 @@ function makeMapStateToProps() {
|
|||||||
isReadOnly: false,
|
isReadOnly: false,
|
||||||
isMuted: isCurrentChannelMuted(state),
|
isMuted: isCurrentChannelMuted(state),
|
||||||
isQuickSwitcherOpen: isModalOpen(state, ModalIdentifiers.QUICK_SWITCH),
|
isQuickSwitcherOpen: isModalOpen(state, ModalIdentifiers.QUICK_SWITCH),
|
||||||
hasGuests: stats.guest_count > 0,
|
hasGuests: stats ? stats.guest_count > 0 : false,
|
||||||
pinnedPostsCount: stats.pinnedpost_count,
|
pinnedPostsCount: stats?.pinnedpost_count || 0,
|
||||||
hasMoreThanOneTeam,
|
hasMoreThanOneTeam,
|
||||||
currentRelativeTeamUrl: getCurrentRelativeTeamUrl(state),
|
currentRelativeTeamUrl: getCurrentRelativeTeamUrl(state),
|
||||||
announcementBarCount: getAnnouncementBarCount(state),
|
announcementBarCount: getAnnouncementBarCount(state),
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import MenuItemViewPinnedPosts from './menu_items/view_pinned_posts';
|
|||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
user: UserProfile;
|
user: UserProfile;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
isFavorite: boolean;
|
isFavorite: boolean;
|
||||||
isReadonly: boolean;
|
isReadonly: boolean;
|
||||||
@@ -69,6 +69,10 @@ export default class ChannelHeaderDropdown extends React.PureComponent<Props> {
|
|||||||
isLicensedForLDAPGroups,
|
isLicensedForLDAPGroups,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const isPrivate = channel.type === Constants.PRIVATE_CHANNEL;
|
const isPrivate = channel.type === Constants.PRIVATE_CHANNEL;
|
||||||
const isGroupConstrained = channel.group_constrained === true;
|
const isGroupConstrained = channel.group_constrained === true;
|
||||||
const channelMembersPermission = isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS : Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS;
|
const channelMembersPermission = isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS : Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS;
|
||||||
@@ -92,7 +96,7 @@ export default class ChannelHeaderDropdown extends React.PureComponent<Props> {
|
|||||||
key={item.id + '_pluginmenuitem'}
|
key={item.id + '_pluginmenuitem'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (item.action) {
|
if (item.action) {
|
||||||
item.action(this.props.channel.id);
|
item.action(channel.id);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
text={item.text}
|
text={item.text}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const getTeammateId = createSelector(
|
|||||||
getCurrentChannel,
|
getCurrentChannel,
|
||||||
getCurrentUserId,
|
getCurrentUserId,
|
||||||
(channel, currentUserId) => {
|
(channel, currentUserId) => {
|
||||||
if (channel.type !== Constants.DM_CHANNEL) {
|
if (channel?.type !== Constants.DM_CHANNEL) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import MobileChannelHeaderDropdownAnimation from './mobile_channel_header_dropdo
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: UserProfile;
|
user: UserProfile;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
teammateId: string | null;
|
teammateId: string | null;
|
||||||
teammateIsBot?: boolean;
|
teammateIsBot?: boolean;
|
||||||
teammateStatus?: string;
|
teammateStatus?: string;
|
||||||
@@ -36,6 +36,10 @@ const MobileChannelHeaderDropdown = ({
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const getChannelTitle = () => {
|
const getChannelTitle = () => {
|
||||||
|
if (!channel) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
if (channel.type === Constants.DM_CHANNEL) {
|
if (channel.type === Constants.DM_CHANNEL) {
|
||||||
if (user.id === teammateId) {
|
if (user.id === teammateId) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ function mapStateToProps(state: GlobalState) {
|
|||||||
const isInvitingPeople = isModalOpen(state, ModalIdentifiers.CHANNEL_INVITE) || isModalOpen(state, ModalIdentifiers.CREATE_DM_CHANNEL);
|
const isInvitingPeople = isModalOpen(state, ModalIdentifiers.CHANNEL_INVITE) || isModalOpen(state, ModalIdentifiers.CREATE_DM_CHANNEL);
|
||||||
const isMobile = getIsMobileView(state);
|
const isMobile = getIsMobileView(state);
|
||||||
|
|
||||||
const isPrivate = channel.type === Constants.PRIVATE_CHANNEL;
|
const isPrivate = channel?.type === Constants.PRIVATE_CHANNEL;
|
||||||
const canManageMembers = haveIChannelPermission(state, currentTeam?.id, channel.id, isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS : Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS);
|
const canManageMembers = haveIChannelPermission(state, currentTeam?.id, channel?.id, isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS : Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS);
|
||||||
const canManageProperties = haveIChannelPermission(state, currentTeam?.id, channel.id, isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_PROPERTIES : Permissions.MANAGE_PUBLIC_CHANNEL_PROPERTIES);
|
const canManageProperties = haveIChannelPermission(state, currentTeam?.id, channel?.id, isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_PROPERTIES : Permissions.MANAGE_PUBLIC_CHANNEL_PROPERTIES);
|
||||||
|
|
||||||
const channelMembers = getProfilesInCurrentChannel(state);
|
const channelMembers = getProfilesInCurrentChannel(state);
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ function mapStateToProps(state: GlobalState) {
|
|||||||
channelMembers,
|
channelMembers,
|
||||||
} as Props;
|
} as Props;
|
||||||
|
|
||||||
if (channel.type === Constants.DM_CHANNEL) {
|
if (channel?.type === Constants.DM_CHANNEL) {
|
||||||
const user = getUser(state, getUserIdFromChannelId(channel.name, currentUser.id));
|
const user = getUser(state, getUserIdFromChannelId(channel.name, currentUser.id));
|
||||||
props.dmUser = {
|
props.dmUser = {
|
||||||
user,
|
user,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export type Props = {
|
|||||||
/*
|
/*
|
||||||
* Object containing information on the current selected channel, used to define BackButton's url
|
* Object containing information on the current selected channel, used to define BackButton's url
|
||||||
*/
|
*/
|
||||||
currentChannel: Channel;
|
currentChannel?: Channel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* String containing the custom branding's text
|
* String containing the custom branding's text
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ function makeMapStateToProps() {
|
|||||||
const userId = getCurrentUserId(state);
|
const userId = getCurrentUserId(state);
|
||||||
const channel = getChannel(state, post.channel_id);
|
const channel = getChannel(state, post.channel_id);
|
||||||
const currentTeam = getCurrentTeam(state);
|
const currentTeam = getCurrentTeam(state);
|
||||||
const team = getTeam(state, channel.team_id);
|
const team = channel ? getTeam(state, channel.team_id) : undefined;
|
||||||
const teamUrl = `${getSiteURL()}/${team?.name || currentTeam?.name}`;
|
const teamUrl = `${getSiteURL()}/${team?.name || currentTeam?.name}`;
|
||||||
const isMilitaryTime = getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false);
|
const isMilitaryTime = getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false);
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ function makeMapStateToProps() {
|
|||||||
isMobileView: getIsMobileView(state),
|
isMobileView: getIsMobileView(state),
|
||||||
timezone: getCurrentTimezone(state),
|
timezone: getCurrentTimezone(state),
|
||||||
isMilitaryTime,
|
isMilitaryTime,
|
||||||
canMove: canWrangler(state, channel.type, threadReplyCount),
|
canMove: channel ? canWrangler(state, channel.type, threadReplyCount) : false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import PanelBody from '../panel/panel_body';
|
|||||||
import Header from '../panel/panel_header';
|
import Header from '../panel/panel_header';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
channelUrl: string;
|
channelUrl: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
draftId: string;
|
draftId: string;
|
||||||
@@ -51,6 +51,7 @@ function ChannelDraft({
|
|||||||
user,
|
user,
|
||||||
value,
|
value,
|
||||||
isRemote,
|
isRemote,
|
||||||
|
id: channelId,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@@ -60,16 +61,20 @@ function ChannelDraft({
|
|||||||
}, [history, channelUrl]);
|
}, [history, channelUrl]);
|
||||||
|
|
||||||
const handleOnDelete = useCallback((id: string) => {
|
const handleOnDelete = useCallback((id: string) => {
|
||||||
dispatch(removeDraft(id, channel.id));
|
dispatch(removeDraft(id, channelId));
|
||||||
}, [dispatch, channel.id]);
|
}, [dispatch, channelId]);
|
||||||
|
|
||||||
const doSubmit = useCallback((id: string, post: Post) => {
|
const doSubmit = useCallback((id: string, post: Post) => {
|
||||||
dispatch(createPost(post, value.fileInfos));
|
dispatch(createPost(post, value.fileInfos));
|
||||||
dispatch(removeDraft(id, channel.id));
|
dispatch(removeDraft(id, channelId));
|
||||||
history.push(channelUrl);
|
history.push(channelUrl);
|
||||||
}, [dispatch, history, value.fileInfos, channel.id, channelUrl]);
|
}, [dispatch, history, value.fileInfos, channelId, channelUrl]);
|
||||||
|
|
||||||
const showPersistNotificationModal = useCallback((id: string, post: Post) => {
|
const showPersistNotificationModal = useCallback((id: string, post: Post) => {
|
||||||
|
if (!channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(openModal({
|
dispatch(openModal({
|
||||||
modalId: ModalIdentifiers.PERSIST_NOTIFICATION_CONFIRM_MODAL,
|
modalId: ModalIdentifiers.PERSIST_NOTIFICATION_CONFIRM_MODAL,
|
||||||
dialogType: PersistNotificationConfirmModal,
|
dialogType: PersistNotificationConfirmModal,
|
||||||
@@ -80,7 +85,7 @@ function ChannelDraft({
|
|||||||
onConfirm: () => doSubmit(id, post),
|
onConfirm: () => doSubmit(id, post),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}, [channel.type, dispatch, doSubmit]);
|
}, [channel, dispatch, doSubmit]);
|
||||||
|
|
||||||
const handleOnSend = useCallback(async (id: string) => {
|
const handleOnSend = useCallback(async (id: string) => {
|
||||||
const post = {} as Post;
|
const post = {} as Post;
|
||||||
@@ -135,7 +140,7 @@ function ChannelDraft({
|
|||||||
remote={isRemote || false}
|
remote={isRemote || false}
|
||||||
/>
|
/>
|
||||||
<PanelBody
|
<PanelBody
|
||||||
channelId={channel.id}
|
channelId={channelId}
|
||||||
displayName={displayName}
|
displayName={displayName}
|
||||||
fileInfos={value.fileInfos}
|
fileInfos={value.fileInfos}
|
||||||
message={value.message}
|
message={value.message}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function makeMapStateToProps() {
|
|||||||
const channel = getChannel(state, ownProps);
|
const channel = getChannel(state, ownProps);
|
||||||
|
|
||||||
const teamId = getCurrentTeamId(state);
|
const teamId = getCurrentTeamId(state);
|
||||||
const channelUrl = getChannelURL(state, channel, teamId);
|
const channelUrl = channel ? getChannelURL(state, channel, teamId) : '';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channel,
|
channel,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import PanelBody from '../panel/panel_body';
|
|||||||
import Header from '../panel/panel_header';
|
import Header from '../panel/panel_header';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
draftId: string;
|
draftId: string;
|
||||||
rootId: UserThread['id'] | UserThreadSynthetic['id'];
|
rootId: UserThread['id'] | UserThreadSynthetic['id'];
|
||||||
@@ -57,29 +57,29 @@ function ThreadDraft({
|
|||||||
}, [thread?.id]);
|
}, [thread?.id]);
|
||||||
|
|
||||||
const onSubmit = useMemo(() => {
|
const onSubmit = useMemo(() => {
|
||||||
if (thread) {
|
if (thread?.id) {
|
||||||
return makeOnSubmit(channel.id, thread.id, '');
|
return makeOnSubmit(value.channelId, thread.id, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => Promise.resolve({data: true});
|
return () => Promise.resolve({data: true});
|
||||||
}, [channel.id, thread?.id]);
|
}, [value.channelId, thread?.id]);
|
||||||
|
|
||||||
const handleOnDelete = useCallback((id: string) => {
|
const handleOnDelete = useCallback((id: string) => {
|
||||||
dispatch(removeDraft(id, channel.id, rootId));
|
dispatch(removeDraft(id, value.channelId, rootId));
|
||||||
}, [channel.id, rootId]);
|
}, [value.channelId, rootId, dispatch]);
|
||||||
|
|
||||||
const handleOnEdit = useCallback(() => {
|
const handleOnEdit = useCallback(() => {
|
||||||
dispatch(selectPost({id: rootId, channel_id: channel.id} as Post));
|
dispatch(selectPost({id: rootId, channel_id: value.channelId} as Post));
|
||||||
}, [channel]);
|
}, [value.channelId, dispatch, rootId]);
|
||||||
|
|
||||||
const handleOnSend = useCallback(async (id: string) => {
|
const handleOnSend = useCallback(async (id: string) => {
|
||||||
await dispatch(onSubmit(value));
|
await dispatch(onSubmit(value));
|
||||||
|
|
||||||
handleOnDelete(id);
|
handleOnDelete(id);
|
||||||
handleOnEdit();
|
handleOnEdit();
|
||||||
}, [value, onSubmit]);
|
}, [value, onSubmit, dispatch, handleOnDelete, handleOnEdit]);
|
||||||
|
|
||||||
if (!thread) {
|
if (!thread || !channel) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ function mapStateToProps(state: GlobalState) {
|
|||||||
teamId,
|
teamId,
|
||||||
channelId,
|
channelId,
|
||||||
maxPostSize: parseInt(config.MaxPostSize || '0', 10) || Constants.DEFAULT_CHARACTER_LIMIT,
|
maxPostSize: parseInt(config.MaxPostSize || '0', 10) || Constants.DEFAULT_CHARACTER_LIMIT,
|
||||||
readOnlyChannel: !isCurrentUserSystemAdmin(state) && channel.name === Constants.DEFAULT_CHANNEL,
|
readOnlyChannel: !isCurrentUserSystemAdmin(state) && channel?.name === Constants.DEFAULT_CHANNEL,
|
||||||
useChannelMentions,
|
useChannelMentions,
|
||||||
isRHSOpened: getIsRhsOpen(state),
|
isRHSOpened: getIsRhsOpen(state),
|
||||||
isEditHistoryShowing: getRhsState(state) === RHSStates.EDIT_HISTORY,
|
isEditHistoryShowing: getRhsState(state) === RHSStates.EDIT_HISTORY,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
channelDisplayName: '',
|
channelDisplayName: '',
|
||||||
channelType: channel.type,
|
channelType: channel?.type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
import type {ConnectedProps} from 'react-redux';
|
|
||||||
import {bindActionCreators} from 'redux';
|
|
||||||
import type {Dispatch} from 'redux';
|
|
||||||
|
|
||||||
import type {Channel} from '@mattermost/types/channels';
|
|
||||||
import type {Post} from '@mattermost/types/posts';
|
|
||||||
|
|
||||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
|
||||||
|
|
||||||
import {openDirectChannelToUserId} from 'actions/channel_actions';
|
|
||||||
import {joinChannelById, switchToChannel} from 'actions/views/channel';
|
|
||||||
import {forwardPost} from 'actions/views/posts';
|
|
||||||
|
|
||||||
import ForwardPostModal from './forward_post_modal';
|
|
||||||
|
|
||||||
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
|
||||||
|
|
||||||
export type ActionProps = {
|
|
||||||
|
|
||||||
// join the selected channel when necessary
|
|
||||||
joinChannelById: (channelId: string) => Promise<ActionResult>;
|
|
||||||
|
|
||||||
// switch to the selected channel
|
|
||||||
switchToChannel: (channel: Channel) => Promise<ActionResult>;
|
|
||||||
|
|
||||||
// switch to the selected channel
|
|
||||||
openDirectChannelToUserId: (userId: string) => Promise<ActionResult<Channel>>;
|
|
||||||
|
|
||||||
// action called to forward the post with an optional comment
|
|
||||||
forwardPost: (post: Post, channelId: Channel, message?: string) => Promise<ActionResult>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OwnProps = {
|
|
||||||
|
|
||||||
// The function called immediately after the modal is hidden
|
|
||||||
onExited?: () => void;
|
|
||||||
|
|
||||||
// the post that is going to be forwarded
|
|
||||||
post: Post;
|
|
||||||
};
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
|
||||||
return {
|
|
||||||
actions: bindActionCreators({
|
|
||||||
joinChannelById,
|
|
||||||
switchToChannel,
|
|
||||||
forwardPost,
|
|
||||||
openDirectChannelToUserId,
|
|
||||||
}, dispatch),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const connector = connect(null, mapDispatchToProps);
|
|
||||||
|
|
||||||
export default connector(ForwardPostModal);
|
|
||||||
@@ -4,11 +4,11 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, {useCallback, useRef, useState} from 'react';
|
import React, {useCallback, useRef, useState} from 'react';
|
||||||
import {FormattedList, FormattedMessage, useIntl} from 'react-intl';
|
import {FormattedList, FormattedMessage, useIntl} from 'react-intl';
|
||||||
import {useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
import type {ValueType} from 'react-select';
|
import type {ValueType} from 'react-select';
|
||||||
|
|
||||||
import {GenericModal} from '@mattermost/components';
|
import {GenericModal} from '@mattermost/components';
|
||||||
import type {PostPreviewMetadata} from '@mattermost/types/posts';
|
import type {Post, PostPreviewMetadata} from '@mattermost/types/posts';
|
||||||
|
|
||||||
import {General, Permissions} from 'mattermost-redux/constants';
|
import {General, Permissions} from 'mattermost-redux/constants';
|
||||||
import {makeGetChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {makeGetChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
@@ -16,6 +16,9 @@ import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles'
|
|||||||
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||||
|
|
||||||
|
import {openDirectChannelToUserId} from 'actions/channel_actions';
|
||||||
|
import {joinChannelById, switchToChannel} from 'actions/views/channel';
|
||||||
|
import {forwardPost} from 'actions/views/posts';
|
||||||
import {getPermalinkURL} from 'selectors/urls';
|
import {getPermalinkURL} from 'selectors/urls';
|
||||||
|
|
||||||
import NotificationBox from 'components/notification_box';
|
import NotificationBox from 'components/notification_box';
|
||||||
@@ -30,16 +33,22 @@ import ForwardPostChannelSelect, {makeSelectedChannelOption} from './forward_pos
|
|||||||
import type {ChannelOption} from './forward_post_channel_select';
|
import type {ChannelOption} from './forward_post_channel_select';
|
||||||
import ForwardPostCommentInput from './forward_post_comment_input';
|
import ForwardPostCommentInput from './forward_post_comment_input';
|
||||||
|
|
||||||
import type {ActionProps, OwnProps, PropsFromRedux} from './index';
|
|
||||||
|
|
||||||
import './forward_post_modal.scss';
|
import './forward_post_modal.scss';
|
||||||
|
|
||||||
export type Props = PropsFromRedux & OwnProps & { actions: ActionProps };
|
type Props = {
|
||||||
|
|
||||||
|
// The function called immediately after the modal is hidden
|
||||||
|
onExited?: () => void;
|
||||||
|
|
||||||
|
// the post that is going to be forwarded
|
||||||
|
post: Post;
|
||||||
|
};
|
||||||
|
|
||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
|
|
||||||
const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
const ForwardPostModal = ({onExited, post}: Props) => {
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const getChannel = makeGetChannel();
|
const getChannel = makeGetChannel();
|
||||||
|
|
||||||
@@ -49,7 +58,7 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
const relativePermaLink = useSelector((state: GlobalState) => (currentTeam ? getPermalinkURL(state, currentTeam.id, post.id) : ''));
|
const relativePermaLink = useSelector((state: GlobalState) => (currentTeam ? getPermalinkURL(state, currentTeam.id, post.id) : ''));
|
||||||
const permaLink = `${getSiteURL()}${relativePermaLink}`;
|
const permaLink = `${getSiteURL()}${relativePermaLink}`;
|
||||||
|
|
||||||
const isPrivateConversation = channel.type !== Constants.OPEN_CHANNEL;
|
const isPrivateConversation = channel?.type !== Constants.OPEN_CHANNEL;
|
||||||
|
|
||||||
const [comment, setComment] = useState('');
|
const [comment, setComment] = useState('');
|
||||||
const [bodyHeight, setBodyHeight] = useState<number>(0);
|
const [bodyHeight, setBodyHeight] = useState<number>(0);
|
||||||
@@ -77,7 +86,7 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
|
|
||||||
const canPostInSelectedChannel = useSelector(
|
const canPostInSelectedChannel = useSelector(
|
||||||
(state: GlobalState) => {
|
(state: GlobalState) => {
|
||||||
const channelId = isPrivateConversation ? channel.id : selectedChannelId;
|
const channelId = isPrivateConversation ? post.channel_id : selectedChannelId;
|
||||||
const isDMChannel = selectedChannel?.details?.type === Constants.DM_CHANNEL;
|
const isDMChannel = selectedChannel?.details?.type === Constants.DM_CHANNEL;
|
||||||
const teamId = isPrivateConversation ? currentTeam?.id : selectedChannel?.details?.team_id;
|
const teamId = isPrivateConversation ? currentTeam?.id : selectedChannel?.details?.team_id;
|
||||||
|
|
||||||
@@ -123,15 +132,15 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
post,
|
post,
|
||||||
post_id: post.id,
|
post_id: post.id,
|
||||||
team_name: currentTeam?.name || '',
|
team_name: currentTeam?.name || '',
|
||||||
channel_display_name: channel.display_name,
|
channel_display_name: channel?.display_name || '',
|
||||||
channel_type: channel.type,
|
channel_type: channel?.type || 'O',
|
||||||
channel_id: channel.id,
|
channel_id: post.channel_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let notification;
|
let notification;
|
||||||
if (isPrivateConversation) {
|
if (isPrivateConversation) {
|
||||||
let notificationText;
|
let notificationText;
|
||||||
if (channel.type === General.PRIVATE_CHANNEL) {
|
if (channel?.type === General.PRIVATE_CHANNEL) {
|
||||||
const channelName = `~${channel.display_name}`;
|
const channelName = `~${channel.display_name}`;
|
||||||
notificationText = (
|
notificationText = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@@ -144,7 +153,7 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const allParticipants = channel.display_name.split(', ');
|
const allParticipants = channel?.display_name.split(', ') || [];
|
||||||
const participants = allParticipants.map((participant) => <strong key={participant}>{participant}</strong>);
|
const participants = allParticipants.map((participant) => <strong key={participant}>{participant}</strong>);
|
||||||
|
|
||||||
notificationText = (
|
notificationText = (
|
||||||
@@ -179,6 +188,10 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
const channelToForward = isPrivateConversation ? makeSelectedChannelOption(channel) : selectedChannel;
|
const channelToForward = isPrivateConversation ? makeSelectedChannelOption(channel) : selectedChannel;
|
||||||
|
|
||||||
if (!channelToForward) {
|
if (!channelToForward) {
|
||||||
@@ -189,7 +202,7 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
|
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
if (type === Constants.DM_CHANNEL && userId) {
|
if (type === Constants.DM_CHANNEL && userId) {
|
||||||
return actions.openDirectChannelToUserId(userId);
|
return dispatch(openDirectChannelToUserId(userId));
|
||||||
}
|
}
|
||||||
return {data: false} as ActionResult;
|
return {data: false} as ActionResult;
|
||||||
}).then(({data}) => {
|
}).then(({data}) => {
|
||||||
@@ -197,20 +210,20 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
channelToForward.details.id = data.id;
|
channelToForward.details.id = data.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions.forwardPost(
|
return dispatch(forwardPost(
|
||||||
post,
|
post,
|
||||||
channelToForward.details,
|
channelToForward.details,
|
||||||
comment,
|
comment,
|
||||||
);
|
));
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (type === Constants.MENTION_MORE_CHANNELS && type === Constants.OPEN_CHANNEL) {
|
if (type === Constants.MENTION_MORE_CHANNELS && type === Constants.OPEN_CHANNEL) {
|
||||||
return actions.joinChannelById(channelToForward.details.id);
|
return dispatch(joinChannelById(channelToForward.details.id));
|
||||||
}
|
}
|
||||||
return {data: false};
|
return {data: false};
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// only switch channels when we are not in a private conversation
|
// only switch channels when we are not in a private conversation
|
||||||
if (!isPrivateConversation) {
|
if (!isPrivateConversation) {
|
||||||
return actions.switchToChannel(channelToForward.details);
|
return dispatch(switchToChannel(channelToForward.details));
|
||||||
}
|
}
|
||||||
return {data: false};
|
return {data: false};
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
@@ -227,7 +240,7 @@ const ForwardPostModal = ({onExited, post, actions}: Props) => {
|
|||||||
defaultMessage: 'Originally posted in ~{channel}',
|
defaultMessage: 'Originally posted in ~{channel}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
channel: channel.display_name,
|
channel: channel?.display_name || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -58,7 +58,7 @@ export type Props = {
|
|||||||
) => Promise<ActionResult<InviteResults>>;
|
) => Promise<ActionResult<InviteResults>>;
|
||||||
};
|
};
|
||||||
currentTeam?: Team;
|
currentTeam?: Team;
|
||||||
currentChannel: Channel;
|
currentChannel?: Channel;
|
||||||
townSquareDisplayName: string;
|
townSquareDisplayName: string;
|
||||||
invitableChannels: Channel[];
|
invitableChannels: Channel[];
|
||||||
emailInvitationsEnabled: boolean;
|
emailInvitationsEnabled: boolean;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export type Props = InviteState & {
|
|||||||
onChannelsInputChange: (channelsInputValue: string) => void;
|
onChannelsInputChange: (channelsInputValue: string) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
currentTeam: Team;
|
currentTeam: Team;
|
||||||
currentChannel: Channel;
|
currentChannel?: Channel;
|
||||||
setCustomMessage: (message: string) => void;
|
setCustomMessage: (message: string) => void;
|
||||||
toggleCustomMessage: () => void;
|
toggleCustomMessage: () => void;
|
||||||
channelsLoader: (value: string, callback?: (channels: Channel[]) => void) => Promise<Channel[]>;
|
channelsLoader: (value: string, callback?: (channels: Channel[]) => void) => Promise<Channel[]>;
|
||||||
|
|||||||
@@ -48,11 +48,14 @@ const getChannelURLAction = (channelId: string, teamId: string, url: string): Th
|
|||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
if (url && isPermalinkURL(url)) {
|
if (url && isPermalinkURL(url)) {
|
||||||
return getHistory().push(url);
|
getHistory().push(url);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = getChannel(state, channelId);
|
const channel = getChannel(state, channelId);
|
||||||
return getHistory().push(getChannelURL(state, channel, teamId));
|
if (channel) {
|
||||||
|
getHistory().push(getChannelURL(state, channel, teamId));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
|
|||||||
@@ -41,8 +41,14 @@ const getUsersAndActionsToDisplay = createSelector(
|
|||||||
channelMember: ChannelMembership;
|
channelMember: ChannelMembership;
|
||||||
};
|
};
|
||||||
} = {};
|
} = {};
|
||||||
const usersToDisplay = [];
|
const usersToDisplay: UserProfile[] = [];
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return {
|
||||||
|
usersToDisplay,
|
||||||
|
actionUserProps,
|
||||||
|
};
|
||||||
|
}
|
||||||
for (let i = 0; i < users.length; i++) {
|
for (let i = 0; i < users.length; i++) {
|
||||||
const user = users[i];
|
const user = users[i];
|
||||||
|
|
||||||
|
|||||||
@@ -104,10 +104,10 @@ const MoveThreadModal = ({onExited, post, actions}: Props) => {
|
|||||||
post,
|
post,
|
||||||
post_id: post.id,
|
post_id: post.id,
|
||||||
team_name: currentTeam?.name || '',
|
team_name: currentTeam?.name || '',
|
||||||
channel_display_name: originalChannel.display_name,
|
channel_display_name: originalChannel?.display_name || '',
|
||||||
channel_type: originalChannel.type,
|
channel_type: originalChannel?.type || 'O',
|
||||||
channel_id: originalChannel.id,
|
channel_id: originalChannel?.id || '',
|
||||||
}), [post, currentTeam?.name, originalChannel.display_name, originalChannel.type, originalChannel.id]);
|
}), [post, currentTeam?.name, originalChannel?.display_name, originalChannel?.type, originalChannel?.id]);
|
||||||
|
|
||||||
const notificationText = formatMessage({
|
const notificationText = formatMessage({
|
||||||
id: 'move_thread_modal.notification.dm_or_gm',
|
id: 'move_thread_modal.notification.dm_or_gm',
|
||||||
@@ -180,7 +180,7 @@ const MoveThreadModal = ({onExited, post, actions}: Props) => {
|
|||||||
defaultMessage: 'Originally posted in ~{channelName}',
|
defaultMessage: 'Originally posted in ~{channelName}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
channelName: originalChannel.display_name,
|
channelName: originalChannel?.display_name || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ import PostEditHistory from './post_edit_history';
|
|||||||
function mapStateToProps(state: GlobalState) {
|
function mapStateToProps(state: GlobalState) {
|
||||||
const selectedPostId = getSelectedPostId(state) || '';
|
const selectedPostId = getSelectedPostId(state) || '';
|
||||||
const originalPost = getPost(state, selectedPostId);
|
const originalPost = getPost(state, selectedPostId);
|
||||||
const channelDisplayName = getCurrentChannel(state) ? getCurrentChannel(state).display_name : getChannel(state, originalPost.channel_id).display_name;
|
const channel = getCurrentChannel(state) ?? getChannel(state, originalPost.channel_id);
|
||||||
|
const channelDisplayName = channel?.display_name || '';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channelDisplayName,
|
channelDisplayName,
|
||||||
|
|||||||
@@ -65,13 +65,13 @@ export default class PostMarkdown extends React.PureComponent<Props> {
|
|||||||
let message = this.props.message;
|
let message = this.props.message;
|
||||||
|
|
||||||
if (this.props.post) {
|
if (this.props.post) {
|
||||||
const renderedSystemMessage = renderSystemMessage(this.props.post,
|
const renderedSystemMessage = this.props.channel ? renderSystemMessage(this.props.post,
|
||||||
this.props.currentTeam?.name ?? '',
|
this.props.currentTeam?.name ?? '',
|
||||||
this.props.channel,
|
this.props.channel,
|
||||||
this.props.hideGuestTags,
|
this.props.hideGuestTags,
|
||||||
this.props.isUserCanManageMembers,
|
this.props.isUserCanManageMembers,
|
||||||
this.props.isMilitaryTime,
|
this.props.isMilitaryTime,
|
||||||
this.props.timezone);
|
this.props.timezone) : null;
|
||||||
if (renderedSystemMessage) {
|
if (renderedSystemMessage) {
|
||||||
return <div>{renderedSystemMessage}</div>;
|
return <div>{renderedSystemMessage}</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import PluggableIntroButtons from './pluggable_intro_buttons';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
fullWidth: boolean;
|
fullWidth: boolean;
|
||||||
locale: string;
|
locale: string;
|
||||||
channelProfiles: UserProfileType[];
|
channelProfiles: UserProfileType[];
|
||||||
@@ -59,6 +59,10 @@ type Props = {
|
|||||||
|
|
||||||
export default class ChannelIntroMessage extends React.PureComponent<Props> {
|
export default class ChannelIntroMessage extends React.PureComponent<Props> {
|
||||||
toggleFavorite = () => {
|
toggleFavorite = () => {
|
||||||
|
if (!this.props.channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.props.isFavorite) {
|
if (this.props.isFavorite) {
|
||||||
this.props.actions.unfavoriteChannel(this.props.channel.id);
|
this.props.actions.unfavoriteChannel(this.props.channel.id);
|
||||||
} else {
|
} else {
|
||||||
@@ -98,6 +102,10 @@ export default class ChannelIntroMessage extends React.PureComponent<Props> {
|
|||||||
centeredIntro = 'channel-intro--centered';
|
centeredIntro = 'channel-intro--centered';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (channel.type === Constants.DM_CHANNEL) {
|
if (channel.type === Constants.DM_CHANNEL) {
|
||||||
return createDMIntroMessage(channel, centeredIntro, currentUser, isFavorite, isMobileView, this.toggleFavorite, teammate, teammateName);
|
return createDMIntroMessage(channel, centeredIntro, currentUser, isFavorite, isMobileView, this.toggleFavorite, teammate, teammateName);
|
||||||
} else if (channel.type === Constants.GM_CHANNEL) {
|
} else if (channel.type === Constants.GM_CHANNEL) {
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ function mapStateToProps(state: GlobalState) {
|
|||||||
const enableUserCreation = config.EnableUserCreation === 'true';
|
const enableUserCreation = config.EnableUserCreation === 'true';
|
||||||
const isReadOnly = false;
|
const isReadOnly = false;
|
||||||
const team = getCurrentTeam(state);
|
const team = getCurrentTeam(state);
|
||||||
const channel = getCurrentChannel(state) || {};
|
const channel = getCurrentChannel(state);
|
||||||
const channelMember = getMyCurrentChannelMembership(state);
|
const channelMember = getMyCurrentChannelMembership(state);
|
||||||
const teammate = getDirectTeammate(state, channel.id);
|
const teammate = channel ? getDirectTeammate(state, channel.id) : undefined;
|
||||||
const currentUser = getCurrentUser(state);
|
const currentUser = getCurrentUser(state);
|
||||||
const creator = getUser(state, channel.creator_id);
|
const creator = channel ? getUser(state, channel.creator_id) : undefined;
|
||||||
|
|
||||||
const usersLimit = 10;
|
const usersLimit = 10;
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function makeMapStateToProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ownProps.metadata.channel_type === General.DM_CHANNEL) {
|
if (ownProps.metadata.channel_type === General.DM_CHANNEL) {
|
||||||
channelDisplayName = getChannel(state, {id: ownProps.metadata.channel_id}).display_name;
|
channelDisplayName = getChannel(state, {id: ownProps.metadata.channel_id})?.display_name || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import type {FakePost, RhsState} from 'types/store/rhs';
|
|||||||
type Props = {
|
type Props = {
|
||||||
currentTeam?: Team;
|
currentTeam?: Team;
|
||||||
posts: Post[];
|
posts: Post[];
|
||||||
channel: Channel | null;
|
channel?: Channel;
|
||||||
selected: Post | FakePost;
|
selected: Post | FakePost;
|
||||||
previousRhsState?: RhsState;
|
previousRhsState?: RhsState;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ function makeMapStateToProps() {
|
|||||||
|
|
||||||
const currentChannelId = getCurrentChannelId(state);
|
const currentChannelId = getCurrentChannelId(state);
|
||||||
|
|
||||||
const unreadCount = getUnreadCount(state, channel.id);
|
const unreadCount = getUnreadCount(state, channel?.id || '');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channel,
|
channel,
|
||||||
isCurrentChannel: channel.id === currentChannelId,
|
isCurrentChannel: channel?.id === currentChannelId,
|
||||||
currentTeamName: currentTeam?.name,
|
currentTeamName: currentTeam?.name,
|
||||||
unreadMentions: unreadCount.mentions,
|
unreadMentions: unreadCount.mentions,
|
||||||
isUnread: unreadCount.showUnread,
|
isUnread: unreadCount.showUnread,
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ function SidebarChannel({
|
|||||||
autoSortedCategoryIds,
|
autoSortedCategoryIds,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [show, setShow] = useState(true);
|
const [show, setShow] = useState(true);
|
||||||
|
if (!channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!currentTeamName) {
|
if (!currentTeamName) {
|
||||||
return null;
|
return null;
|
||||||
@@ -43,7 +46,7 @@ function SidebarChannel({
|
|||||||
|
|
||||||
function setRef(refMethod?: (element: HTMLLIElement) => void) {
|
function setRef(refMethod?: (element: HTMLLIElement) => void) {
|
||||||
return (ref: HTMLLIElement) => {
|
return (ref: HTMLLIElement) => {
|
||||||
setChannelRef(channel.id, ref);
|
setChannelRef(channel?.id || '', ref);
|
||||||
refMethod?.(ref);
|
refMethod?.(ref);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import type {RhsState} from 'types/store/rhs';
|
|||||||
export type Props = {
|
export type Props = {
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
channel: Channel;
|
channel?: Channel;
|
||||||
team?: Team;
|
team?: Team;
|
||||||
teamId: Team['id'];
|
teamId: Team['id'];
|
||||||
productId: ProductIdentifier;
|
productId: ProductIdentifier;
|
||||||
@@ -44,7 +44,7 @@ export type Props = {
|
|||||||
isPluginView: boolean;
|
isPluginView: boolean;
|
||||||
isPostEditHistory: boolean;
|
isPostEditHistory: boolean;
|
||||||
previousRhsState: RhsState;
|
previousRhsState: RhsState;
|
||||||
rhsChannel: Channel;
|
rhsChannel?: Channel;
|
||||||
selectedPostId: string;
|
selectedPostId: string;
|
||||||
selectedPostCardId: string;
|
selectedPostCardId: string;
|
||||||
actions: {
|
actions: {
|
||||||
@@ -150,11 +150,11 @@ export default class SidebarRight extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {actions, isChannelFiles, isPinnedPosts, rhsChannel, channel} = this.props;
|
const {actions, isChannelFiles, isPinnedPosts, rhsChannel, channel} = this.props;
|
||||||
if (isPinnedPosts && prevProps.isPinnedPosts === isPinnedPosts && rhsChannel.id !== prevProps.rhsChannel.id) {
|
if (isPinnedPosts && prevProps.isPinnedPosts === isPinnedPosts && rhsChannel && rhsChannel.id !== prevProps.rhsChannel?.id) {
|
||||||
actions.showPinnedPosts(rhsChannel.id);
|
actions.showPinnedPosts(rhsChannel.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChannelFiles && prevProps.isChannelFiles === isChannelFiles && rhsChannel.id !== prevProps.rhsChannel.id) {
|
if (isChannelFiles && prevProps.isChannelFiles === isChannelFiles && rhsChannel && rhsChannel.id !== prevProps.rhsChannel?.id) {
|
||||||
actions.showChannelFiles(rhsChannel.id);
|
actions.showChannelFiles(rhsChannel.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1452,7 +1452,7 @@ export class AppCommandParser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// getChannel gets the channel in which the user is typing the command
|
// getChannel gets the channel in which the user is typing the command
|
||||||
private getChannel = (): Channel | null => {
|
private getChannel = (): Channel | undefined => {
|
||||||
const state = this.store.getState();
|
const state = this.store.getState();
|
||||||
return selectChannel(state, this.channelID);
|
return selectChannel(state, this.channelID);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function makeMapStateToProps() {
|
|||||||
|
|
||||||
let postIds: string[] = [];
|
let postIds: string[] = [];
|
||||||
let userThread: UserThread | null = null;
|
let userThread: UserThread | null = null;
|
||||||
let channel: Channel | null = null;
|
let channel: Channel | undefined;
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
postIds = getPostIdsForThread(state, selected.id);
|
postIds = getPostIdsForThread(state, selected.id);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export type Props = Attrs & {
|
|||||||
isCollapsedThreadsEnabled: boolean;
|
isCollapsedThreadsEnabled: boolean;
|
||||||
appsEnabled: boolean;
|
appsEnabled: boolean;
|
||||||
userThread?: UserThread | null;
|
userThread?: UserThread | null;
|
||||||
channel: Channel | null;
|
channel?: Channel;
|
||||||
selected?: Post | FakePost;
|
selected?: Post | FakePost;
|
||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
currentTeamId: string;
|
currentTeamId: string;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function makeGetRootPosts() {
|
|||||||
return Object.values(allPosts).filter((post) => {
|
return Object.values(allPosts).filter((post) => {
|
||||||
return (
|
return (
|
||||||
post.root_id === '' &&
|
post.root_id === '' &&
|
||||||
post.channel_id === channel.id &&
|
post.channel_id === channel?.id &&
|
||||||
post.state !== Posts.POST_DELETED
|
post.state !== Posts.POST_DELETED
|
||||||
);
|
);
|
||||||
}).reduce((map: Record<string, boolean>, obj) => {
|
}).reduce((map: Record<string, boolean>, obj) => {
|
||||||
|
|||||||
@@ -1279,7 +1279,7 @@ export function favoriteChannel(channelId: string): ActionFuncAsync {
|
|||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const channel = getChannelSelector(state, channelId);
|
const channel = getChannelSelector(state, channelId);
|
||||||
const category = getCategoryInTeamByType(state, channel.team_id || getCurrentTeamId(state), CategoryTypes.FAVORITES);
|
const category = getCategoryInTeamByType(state, channel?.team_id || getCurrentTeamId(state), CategoryTypes.FAVORITES);
|
||||||
|
|
||||||
Client4.trackEvent('action', 'action_channels_favorite');
|
Client4.trackEvent('action', 'action_channels_favorite');
|
||||||
|
|
||||||
@@ -1296,6 +1296,10 @@ export function unfavoriteChannel(channelId: string): ActionFuncAsync {
|
|||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const channel = getChannelSelector(state, channelId);
|
const channel = getChannelSelector(state, channelId);
|
||||||
|
if (!channel) {
|
||||||
|
return {data: false};
|
||||||
|
}
|
||||||
|
|
||||||
const category = getCategoryInTeamByType(
|
const category = getCategoryInTeamByType(
|
||||||
state,
|
state,
|
||||||
channel.team_id || getCurrentTeamId(state),
|
channel.team_id || getCurrentTeamId(state),
|
||||||
|
|||||||
@@ -424,13 +424,16 @@ export function decrementThreadCounts(post: ExtendedPost): ActionFunc {
|
|||||||
const channel = getChannel(state, post.channel_id);
|
const channel = getChannel(state, post.channel_id);
|
||||||
const teamId = channel?.team_id || getCurrentTeamId(state);
|
const teamId = channel?.team_id || getCurrentTeamId(state);
|
||||||
|
|
||||||
dispatch({
|
if (channel) {
|
||||||
type: ThreadTypes.DECREMENT_THREAD_COUNTS,
|
dispatch({
|
||||||
teamId,
|
type: ThreadTypes.DECREMENT_THREAD_COUNTS,
|
||||||
replies: thread.unread_replies,
|
teamId,
|
||||||
mentions: thread.unread_mentions,
|
replies: thread.unread_replies,
|
||||||
channelType: channel.type,
|
mentions: thread.unread_mentions,
|
||||||
});
|
channelType: channel.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {data: true};
|
return {data: true};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ export function getChannelMember(state: GlobalState, channelId: string, userId:
|
|||||||
// - The display_name set to the other user(s) names, following the Teammate Name Display setting
|
// - The display_name set to the other user(s) names, following the Teammate Name Display setting
|
||||||
// - The teammate_id for DM channels
|
// - The teammate_id for DM channels
|
||||||
// - The status of the other user in a DM channel
|
// - The status of the other user in a DM channel
|
||||||
export function makeGetChannel(): (state: GlobalState, props: {id: string}) => Channel {
|
export function makeGetChannel(): (state: GlobalState, props: {id: string}) => Channel | undefined {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
'makeGetChannel',
|
'makeGetChannel',
|
||||||
getCurrentUserId,
|
getCurrentUserId,
|
||||||
@@ -183,11 +183,11 @@ export function makeGetChannel(): (state: GlobalState, props: {id: string}) => C
|
|||||||
|
|
||||||
// getChannel returns a channel as it exists in the store without filling in any additional details such as the
|
// getChannel returns a channel as it exists in the store without filling in any additional details such as the
|
||||||
// display_name for DM/GM channels.
|
// display_name for DM/GM channels.
|
||||||
export function getChannel(state: GlobalState, id: string) {
|
export function getChannel(state: GlobalState, id: string): Channel | undefined {
|
||||||
return getAllChannels(state)[id];
|
return getAllChannels(state)[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMyChannelMembership(state: GlobalState, channelId: string): ChannelMembership {
|
export function getMyChannelMembership(state: GlobalState, channelId: string): ChannelMembership | undefined {
|
||||||
return getMyChannelMemberships(state)[channelId];
|
return getMyChannelMemberships(state)[channelId];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ export function makeGetChannelsForIds(): (state: GlobalState, ids: string[]) =>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCurrentChannel: (state: GlobalState) => Channel = createSelector(
|
export const getCurrentChannel: (state: GlobalState) => Channel | undefined = createSelector(
|
||||||
'getCurrentChannel',
|
'getCurrentChannel',
|
||||||
getAllChannels,
|
getAllChannels,
|
||||||
getCurrentChannelId,
|
getCurrentChannelId,
|
||||||
@@ -255,7 +255,7 @@ export const getMyChannelMember: (state: GlobalState, channelId: string) => Chan
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getCurrentChannelStats: (state: GlobalState) => ChannelStats = createSelector(
|
export const getCurrentChannelStats: (state: GlobalState) => ChannelStats | undefined = createSelector(
|
||||||
'getCurrentChannelStats',
|
'getCurrentChannelStats',
|
||||||
getAllChannelStats,
|
getAllChannelStats,
|
||||||
getCurrentChannelId,
|
getCurrentChannelId,
|
||||||
@@ -296,7 +296,7 @@ export const isMutedChannel: (state: GlobalState, channelId: string) => boolean
|
|||||||
export const isCurrentChannelArchived: (state: GlobalState) => boolean = createSelector(
|
export const isCurrentChannelArchived: (state: GlobalState) => boolean = createSelector(
|
||||||
'isCurrentChannelArchived',
|
'isCurrentChannelArchived',
|
||||||
getCurrentChannel,
|
getCurrentChannel,
|
||||||
(channel) => channel.delete_at !== 0,
|
(channel) => channel?.delete_at !== 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const isCurrentChannelDefault: (state: GlobalState) => boolean = createSelector(
|
export const isCurrentChannelDefault: (state: GlobalState) => boolean = createSelector(
|
||||||
@@ -313,15 +313,15 @@ export function isChannelReadOnlyById(state: GlobalState, channelId: string): bo
|
|||||||
return isChannelReadOnly(state, getChannel(state, channelId));
|
return isChannelReadOnly(state, getChannel(state, channelId));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isChannelReadOnly(state: GlobalState, channel: Channel): boolean {
|
export function isChannelReadOnly(state: GlobalState, channel?: Channel): boolean {
|
||||||
return channel && channel.name === General.DEFAULT_CHANNEL && !isCurrentUserSystemAdmin(state);
|
return Boolean(channel && channel.name === General.DEFAULT_CHANNEL && !isCurrentUserSystemAdmin(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getChannelMessageCounts(state: GlobalState): RelationOneToOne<Channel, ChannelMessageCount> {
|
export function getChannelMessageCounts(state: GlobalState): RelationOneToOne<Channel, ChannelMessageCount> {
|
||||||
return state.entities.channels.messageCounts;
|
return state.entities.channels.messageCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getChannelMessageCount(state: GlobalState, channelId: string): ChannelMessageCount {
|
export function getChannelMessageCount(state: GlobalState, channelId: string): ChannelMessageCount | undefined {
|
||||||
return getChannelMessageCounts(state)[channelId];
|
return getChannelMessageCounts(state)[channelId];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,8 +334,8 @@ export const countCurrentChannelUnreadMessages: (state: GlobalState) => number =
|
|||||||
getCurrentChannelMessageCount,
|
getCurrentChannelMessageCount,
|
||||||
getMyCurrentChannelMembership,
|
getMyCurrentChannelMembership,
|
||||||
isCollapsedThreadsEnabled,
|
isCollapsedThreadsEnabled,
|
||||||
(messageCount: ChannelMessageCount, membership?: ChannelMembership, crtEnabled?: boolean): number => {
|
(messageCount?: ChannelMessageCount, membership?: ChannelMembership, crtEnabled?: boolean): number => {
|
||||||
if (!membership) {
|
if (!membership || !messageCount) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return crtEnabled ? messageCount.root - membership.msg_count_root : messageCount.total - membership.msg_count;
|
return crtEnabled ? messageCount.root - membership.msg_count_root : messageCount.total - membership.msg_count;
|
||||||
@@ -348,7 +348,7 @@ export function makeGetChannelUnreadCount(): (state: GlobalState, channelId: str
|
|||||||
(state: GlobalState, channelId: string) => getChannelMessageCount(state, channelId),
|
(state: GlobalState, channelId: string) => getChannelMessageCount(state, channelId),
|
||||||
(state: GlobalState, channelId: string) => getMyChannelMembership(state, channelId),
|
(state: GlobalState, channelId: string) => getMyChannelMembership(state, channelId),
|
||||||
isCollapsedThreadsEnabled,
|
isCollapsedThreadsEnabled,
|
||||||
(messageCount: ChannelMessageCount, member: ChannelMembership, crtEnabled) =>
|
(messageCount: ChannelMessageCount | undefined, member: ChannelMembership | undefined, crtEnabled) =>
|
||||||
calculateUnreadCount(messageCount, member, crtEnabled),
|
calculateUnreadCount(messageCount, member, crtEnabled),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -878,7 +878,7 @@ export const canManageChannelMembers: (state: GlobalState) => boolean = createSe
|
|||||||
Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS,
|
Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
channel: Channel,
|
channel: Channel | undefined,
|
||||||
managePrivateMembers: boolean,
|
managePrivateMembers: boolean,
|
||||||
managePublicMembers: boolean,
|
managePublicMembers: boolean,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export const haveIGroupPermission: (state: GlobalState, groupID: string, permiss
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export function haveIChannelPermission(state: GlobalState, teamId: string | undefined, channelId: string, permission: string): boolean {
|
export function haveIChannelPermission(state: GlobalState, teamId: string | undefined, channelId: string | undefined, permission: string): boolean {
|
||||||
if (getMySystemPermissions(state).has(permission)) {
|
if (getMySystemPermissions(state).has(permission)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,11 @@ export function haveIChannelPermission(state: GlobalState, teamId: string | unde
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMyPermissionsByChannel(state)[channelId]?.has(permission);
|
if (channelId) {
|
||||||
|
return getMyPermissionsByChannel(state)[channelId]?.has(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function haveICurrentTeamPermission(state: GlobalState, permission: string): boolean {
|
export function haveICurrentTeamPermission(state: GlobalState, permission: string): boolean {
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ export function getGroupDisplayNameFromUserIds(userIds: Set<string>, profiles: I
|
|||||||
return names.sort(sortUsernames).join(', ');
|
return names.sort(sortUsernames).join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDefault(channel: Channel): boolean {
|
export function isDefault(channel?: Channel): boolean {
|
||||||
return channel.name === General.DEFAULT_CHANNEL;
|
return channel?.name === General.DEFAULT_CHANNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function completeDirectGroupInfo(usersState: UsersState, teammateNameDisplay: string, channel: Channel, omitCurrentUser = true) {
|
export function completeDirectGroupInfo(usersState: UsersState, teammateNameDisplay: string, channel: Channel, omitCurrentUser = true) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import type {PluginComponent} from 'types/store/plugins';
|
|||||||
import './call_button.scss';
|
import './call_button.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentChannel: Channel;
|
currentChannel?: Channel;
|
||||||
channelMember?: ChannelMembership;
|
channelMember?: ChannelMembership;
|
||||||
pluginCallComponents: PluginComponent[];
|
pluginCallComponents: PluginComponent[];
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function findNextUnreadChannelId(curChannelId: string, allChannelIds: str
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isArchivedChannel(channel: Channel) {
|
export function isArchivedChannel(channel?: Channel) {
|
||||||
return Boolean(channel && channel.delete_at !== 0);
|
return Boolean(channel && channel.delete_at !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export function getImageSrc(src: string, hasImageProxy = false): string {
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canDeletePost(state: GlobalState, post: Post, channel: Channel): boolean {
|
export function canDeletePost(state: GlobalState, post: Post, channel?: Channel): boolean {
|
||||||
if (post.type === Constants.PostTypes.FAKE_PARENT_DELETED) {
|
if (post.type === Constants.PostTypes.FAKE_PARENT_DELETED) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -645,6 +645,9 @@ export function areConsecutivePostsBySameUser(post: Post, previousPost: Post): b
|
|||||||
// Note: In the case of DM_CHANNEL, users must be fetched beforehand.
|
// Note: In the case of DM_CHANNEL, users must be fetched beforehand.
|
||||||
export function getPostURL(state: GlobalState, post: Post): string {
|
export function getPostURL(state: GlobalState, post: Post): string {
|
||||||
const channel = getChannel(state, post.channel_id);
|
const channel = getChannel(state, post.channel_id);
|
||||||
|
if (!channel) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
const currentUserId = getCurrentUserId(state);
|
const currentUserId = getCurrentUserId(state);
|
||||||
const team = getTeam(state, channel.team_id || getCurrentTeamId(state));
|
const team = getTeam(state, channel.team_id || getCurrentTeamId(state));
|
||||||
if (!team) {
|
if (!team) {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user