mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-27 05:37:15 -05:00
MM-66940 Fix layout shift in ChannelView during loading (#37652)
* MM-69940 Fix height of AdvancedTextEditor placeholder while loading The previous height included the margin which it shouldn't have. The 100% height on the post list also seemed to cause its height to change as well. That 98px assumes that this is the empty AdvancedTextEditor which is likely the most common case. * MM-69940 Change ChannelView to not split code as much I don't think this code splitting was necessary given we would always immediately load those components right away whenever the ChannelView is shown. It's not like the contents of a modal or the routing where we only need the async component conditionally. I did this so that the height of the PostView would change less while the app is loading to prevent layout shift and make accurate scrolling easier. * Move getPopoutChannelTitle to fix circular imports and update snapshots
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
.AdvancedTextEditor__skeleton {
|
||||
display: flex;
|
||||
height: 122px;
|
||||
height: 98px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-left: 10px;
|
||||
|
||||
+16
-16
@@ -84,7 +84,7 @@ exports[`components/ChannelHeader should match snapshot with last active display
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -165,7 +165,7 @@ exports[`components/ChannelHeader should match snapshot with no last active disp
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -263,7 +263,7 @@ exports[`components/ChannelHeader should render active channel files 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -361,7 +361,7 @@ exports[`components/ChannelHeader should render active flagged posts 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -459,7 +459,7 @@ exports[`components/ChannelHeader should render active mentions posts 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -557,7 +557,7 @@ exports[`components/ChannelHeader should render active pinned posts 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -655,7 +655,7 @@ exports[`components/ChannelHeader should render archived view 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -763,7 +763,7 @@ exports[`components/ChannelHeader should render correct menu when muted 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -861,7 +861,7 @@ exports[`components/ChannelHeader should render not active channel files 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -953,7 +953,7 @@ exports[`components/ChannelHeader should render properly when custom status is e
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1048,7 +1048,7 @@ exports[`components/ChannelHeader should render properly when custom status is s
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1146,7 +1146,7 @@ exports[`components/ChannelHeader should render properly when empty 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1244,7 +1244,7 @@ exports[`components/ChannelHeader should render properly when populated 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1342,7 +1342,7 @@ exports[`components/ChannelHeader should render properly when populated with cha
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1543,7 +1543,7 @@ exports[`components/ChannelHeader should render shared view 1`] = `
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1657,7 +1657,7 @@ exports[`components/ChannelHeader should render the pinned icon with the pinned
|
||||
id="channel-info-btn"
|
||||
>
|
||||
<i
|
||||
class="Icon-esDcos cHAVtG icon-information-outline"
|
||||
class="Icon-clPswv hCFmLO icon-information-outline"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@ import type {WrappedComponentProps} from 'react-intl';
|
||||
|
||||
import {WithTooltip} from '@mattermost/shared/components/tooltip';
|
||||
|
||||
import {getPopoutChannelTitle} from 'components/channel_popout/channel_popout';
|
||||
import CustomStatusEmoji from 'components/custom_status/custom_status_emoji';
|
||||
import CustomStatusText from 'components/custom_status/custom_status_text';
|
||||
import PopoutButton from 'components/popout_button';
|
||||
@@ -25,7 +24,7 @@ import {
|
||||
NotificationLevels,
|
||||
RHSStates,
|
||||
} from 'utils/constants';
|
||||
import {canPopout, isChannelPopoutWindow, popoutChannel} from 'utils/popouts/popout_windows';
|
||||
import {canPopout, getPopoutChannelTitle, isChannelPopoutWindow, popoutChannel} from 'utils/popouts/popout_windows';
|
||||
import {isEmptyObject} from 'utils/utils';
|
||||
|
||||
import ChannelHeaderText from './channel_header_text';
|
||||
|
||||
+1
-4
@@ -13,11 +13,8 @@ import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
import MenuItemOpenInNewWindow from './open_in_new_window';
|
||||
|
||||
jest.mock('components/channel_popout/channel_popout', () => ({
|
||||
getPopoutChannelTitle: jest.fn(() => ({id: 'test.title', defaultMessage: 'Test Title'})),
|
||||
}));
|
||||
|
||||
jest.mock('utils/popouts/popout_windows', () => ({
|
||||
getPopoutChannelTitle: jest.fn(() => ({id: 'test.title', defaultMessage: 'Test Title'})),
|
||||
isChannelPopoutWindow: jest.fn(() => false),
|
||||
popoutChannel: jest.fn(),
|
||||
canPopout: jest.fn(() => true),
|
||||
|
||||
+1
-2
@@ -11,13 +11,12 @@ import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getUserIdFromChannelName} from 'mattermost-redux/utils/channel_utils';
|
||||
|
||||
import {getPopoutChannelTitle} from 'components/channel_popout/channel_popout';
|
||||
import * as Menu from 'components/menu';
|
||||
import PopoutMenuItem, {type PopoutMenuItemProps} from 'components/popout_menu_item';
|
||||
|
||||
import {getChannelRoutePathAndIdentifier} from 'utils/channel_utils';
|
||||
import {Constants} from 'utils/constants';
|
||||
import {popoutChannel} from 'utils/popouts/popout_windows';
|
||||
import {getPopoutChannelTitle, popoutChannel} from 'utils/popouts/popout_windows';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
|
||||
@@ -12,10 +12,9 @@ import {selectTeam} from 'mattermost-redux/actions/teams';
|
||||
import {useTeamByName} from 'components/common/hooks/use_team';
|
||||
|
||||
import {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
|
||||
import {getPopoutChannelTitle} from 'utils/popouts/popout_windows';
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
import {getPopoutChannelTitle} from './channel_popout';
|
||||
|
||||
import ChannelPopout from './index';
|
||||
|
||||
const MOCK_ACTION = {type: 'MOCK'};
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useDispatch, useSelector} from 'react-redux';
|
||||
import {useParams} from 'react-router-dom';
|
||||
|
||||
import {isDesktopApp} from '@mattermost/shared/utils/user_agent';
|
||||
import type {ChannelType} from '@mattermost/types/channels';
|
||||
|
||||
import {fetchMyCategories} from 'mattermost-redux/actions/channel_categories';
|
||||
import {fetchChannelsAndMembers, getChannelStats} from 'mattermost-redux/actions/channels';
|
||||
@@ -23,19 +22,12 @@ import LoadingScreen from 'components/loading_screen';
|
||||
import SidebarRight from 'components/sidebar_right';
|
||||
import UnreadsStatusHandler from 'components/unreads_status_handler';
|
||||
|
||||
import Constants from 'utils/constants';
|
||||
import {getPopoutChannelTitle} from 'utils/popouts/popout_windows';
|
||||
import usePopoutFocus from 'utils/popouts/use_popout_focus';
|
||||
import usePopoutTitle from 'utils/popouts/use_popout_title';
|
||||
|
||||
import './channel_popout.scss';
|
||||
|
||||
export function getPopoutChannelTitle(channelType?: ChannelType) {
|
||||
if (channelType === Constants.DM_CHANNEL || channelType === Constants.GM_CHANNEL) {
|
||||
return {id: 'channel_popout.title.dm', defaultMessage: '{channelName} - {serverName}'};
|
||||
}
|
||||
return {id: 'channel_popout.title', defaultMessage: '{channelName} - {teamName} - {serverName}'};
|
||||
}
|
||||
|
||||
export default function ChannelPopout() {
|
||||
const dispatch = useDispatch();
|
||||
const {team: teamName, postid} = useParams<{team: string; path: string; identifier: string; postid?: string}>();
|
||||
|
||||
+58
-29
@@ -7,14 +7,25 @@ exports[`components/channel_view Should match snapshot if channel is archived 1`
|
||||
id="app-content"
|
||||
>
|
||||
<div
|
||||
data-testid="FileUploadOverlay"
|
||||
/>
|
||||
<div
|
||||
data-testid="ChannelHeader"
|
||||
/>
|
||||
<div
|
||||
data-testid="ChannelBanner"
|
||||
/>
|
||||
class="file-overlay hidden center-file-overlay"
|
||||
id="centerChannelFileDropOverlay"
|
||||
>
|
||||
<div
|
||||
class="overlay__indent"
|
||||
>
|
||||
<div
|
||||
class="overlay__circle vertical"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="overlay__files"
|
||||
loading="lazy"
|
||||
src=""
|
||||
/>
|
||||
Drop a file to upload it.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-channel-id="channelId"
|
||||
data-testid="deferred-post-view"
|
||||
@@ -50,14 +61,25 @@ exports[`components/channel_view Should match snapshot if channel is deactivated
|
||||
id="app-content"
|
||||
>
|
||||
<div
|
||||
data-testid="FileUploadOverlay"
|
||||
/>
|
||||
<div
|
||||
data-testid="ChannelHeader"
|
||||
/>
|
||||
<div
|
||||
data-testid="ChannelBanner"
|
||||
/>
|
||||
class="file-overlay hidden center-file-overlay"
|
||||
id="centerChannelFileDropOverlay"
|
||||
>
|
||||
<div
|
||||
class="overlay__indent"
|
||||
>
|
||||
<div
|
||||
class="overlay__circle vertical"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="overlay__files"
|
||||
loading="lazy"
|
||||
src=""
|
||||
/>
|
||||
Drop a file to upload it.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-channel-id="channelId"
|
||||
data-testid="deferred-post-view"
|
||||
@@ -92,14 +114,25 @@ exports[`components/channel_view Should match snapshot with base props 1`] = `
|
||||
id="app-content"
|
||||
>
|
||||
<div
|
||||
data-testid="FileUploadOverlay"
|
||||
/>
|
||||
<div
|
||||
data-testid="ChannelHeader"
|
||||
/>
|
||||
<div
|
||||
data-testid="ChannelBanner"
|
||||
/>
|
||||
class="file-overlay hidden center-file-overlay"
|
||||
id="centerChannelFileDropOverlay"
|
||||
>
|
||||
<div
|
||||
class="overlay__indent"
|
||||
>
|
||||
<div
|
||||
class="overlay__circle vertical"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="overlay__files"
|
||||
loading="lazy"
|
||||
src=""
|
||||
/>
|
||||
Drop a file to upload it.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-channel-id="channelId"
|
||||
data-testid="deferred-post-view"
|
||||
@@ -108,11 +141,7 @@ exports[`components/channel_view Should match snapshot with base props 1`] = `
|
||||
class="post-create__container AdvancedTextEditor__ctr"
|
||||
data-testid="post-create"
|
||||
id="post-create"
|
||||
>
|
||||
<div
|
||||
data-testid="AdvancedCreatePost"
|
||||
/>
|
||||
</div>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {lazy} from 'react';
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import type {RouteComponentProps} from 'react-router-dom';
|
||||
|
||||
import {Button} from '@mattermost/shared/components/button';
|
||||
|
||||
import {makeAsyncComponent} from 'components/async_load';
|
||||
import AdvancedCreatePost from 'components/advanced_create_post';
|
||||
import ChannelBanner from 'components/channel_banner/channel_banner';
|
||||
import ChannelBookmarks from 'components/channel_bookmarks';
|
||||
import ChannelHeader from 'components/channel_header';
|
||||
import deferComponentRender from 'components/deferComponentRender';
|
||||
import {DropOverlayIdCenterChannel} from 'components/file_upload_overlay/file_upload_overlay';
|
||||
import {DropOverlayIdCenterChannel, FileUploadOverlay} from 'components/file_upload_overlay/file_upload_overlay';
|
||||
import PostView from 'components/post_view';
|
||||
|
||||
import WebSocketClient from 'client/web_websocket_client';
|
||||
@@ -19,12 +22,6 @@ import InputLoading from './input_loading';
|
||||
|
||||
import type {PropsFromRedux} from './index';
|
||||
|
||||
const ChannelHeader = makeAsyncComponent('ChannelHeader', lazy(() => import('components/channel_header')));
|
||||
const FileUploadOverlay = makeAsyncComponent('FileUploadOverlay', lazy(() => import('components/file_upload_overlay')));
|
||||
const ChannelBookmarks = makeAsyncComponent('ChannelBookmarks', lazy(() => import('components/channel_bookmarks')));
|
||||
const AdvancedCreatePost = makeAsyncComponent('AdvancedCreatePost', lazy(() => import('components/advanced_create_post')));
|
||||
const ChannelBanner = makeAsyncComponent('ChannelBanner', lazy(() => import('components/channel_banner/channel_banner')));
|
||||
|
||||
export type Props = PropsFromRedux & RouteComponentProps<{
|
||||
postid?: string;
|
||||
}>;
|
||||
|
||||
@@ -134,7 +134,6 @@
|
||||
|
||||
#post-list {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
flex: 1 1 auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
import type {PopoutViewProps} from '@mattermost/desktop-api';
|
||||
import {isDesktopApp} from '@mattermost/shared/utils/user_agent';
|
||||
import type {ChannelType} from '@mattermost/types/channels';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import {RHSStates} from 'utils/constants';
|
||||
import Constants, {RHSStates} from 'utils/constants';
|
||||
import DesktopApp from 'utils/desktop_api';
|
||||
import {getBasePath} from 'utils/url';
|
||||
|
||||
@@ -24,6 +25,13 @@ export function registerRHSPluginPopoutListener(pluginId: string, onPopoutOpened
|
||||
pluginPopoutListeners.set(pluginId, onPopoutOpened);
|
||||
}
|
||||
|
||||
export function getPopoutChannelTitle(channelType?: ChannelType) {
|
||||
if (channelType === Constants.DM_CHANNEL || channelType === Constants.GM_CHANNEL) {
|
||||
return {id: 'channel_popout.title.dm', defaultMessage: '{channelName} - {serverName}'};
|
||||
}
|
||||
return {id: 'channel_popout.title', defaultMessage: '{channelName} - {teamName} - {serverName}'};
|
||||
}
|
||||
|
||||
export const FOCUS_REPLY_POST = 'focus-reply-post';
|
||||
export async function popoutThread(
|
||||
titleTemplate: string,
|
||||
|
||||
Reference in New Issue
Block a user