Fix autofocus on load (#28090)
* Fix autofocus on load * Address feedback * Fix styles lint * Revert unintended change * fix tests * Update text
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
7232feecf7
Коммит
92793928bc
@@ -1,5 +1,20 @@
|
||||
@import 'utils/variables';
|
||||
|
||||
.AdvancedTextEditor__skeleton {
|
||||
display: flex;
|
||||
height: 122px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-left: 10px;
|
||||
border: 2px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
border-radius: 4px;
|
||||
margin: 0 24px 24px;
|
||||
color: rgba(var(--center-channel-color-rgb), 0.75);
|
||||
.btn {
|
||||
margin: 10px
|
||||
}
|
||||
}
|
||||
|
||||
.AdvancedTextEditor {
|
||||
&__ctr {
|
||||
form {
|
||||
|
||||
@@ -87,6 +87,8 @@ const useTextboxFocus = (
|
||||
if (isRHS && shouldFocusRHS) {
|
||||
focusTextbox();
|
||||
dispatch(focusedRHS());
|
||||
} else if (!isRHS && !shouldFocusRHS) {
|
||||
focusTextbox();
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ exports[`components/channel_view Should match snapshot if channel is archived 1`
|
||||
"url": "/team/channel/channelId",
|
||||
}
|
||||
}
|
||||
missingChannelRole={false}
|
||||
teamUrl="/team"
|
||||
viewArchivedChannels={false}
|
||||
/>
|
||||
@@ -84,6 +85,7 @@ exports[`components/channel_view Should match snapshot if channel is deactivated
|
||||
"url": "/team/channel/channelId",
|
||||
}
|
||||
}
|
||||
missingChannelRole={false}
|
||||
teamUrl="/team"
|
||||
viewArchivedChannels={false}
|
||||
/>
|
||||
@@ -141,6 +143,7 @@ exports[`components/channel_view Should match snapshot with base props 1`] = `
|
||||
"url": "/team/channel/channelId",
|
||||
}
|
||||
}
|
||||
missingChannelRole={false}
|
||||
teamUrl="/team"
|
||||
viewArchivedChannels={false}
|
||||
/>
|
||||
|
||||
@@ -26,6 +26,7 @@ describe('components/channel_view', () => {
|
||||
isFirstAdmin: false,
|
||||
enableWebSocketEventScope: false,
|
||||
isChannelBookmarksEnabled: false,
|
||||
missingChannelRole: false,
|
||||
};
|
||||
|
||||
it('Should match snapshot with base props', () => {
|
||||
|
||||
@@ -12,6 +12,8 @@ import PostView from 'components/post_view';
|
||||
|
||||
import WebSocketClient from 'client/web_websocket_client';
|
||||
|
||||
import InputLoading from './input_loading';
|
||||
|
||||
import type {PropsFromRedux} from './index';
|
||||
|
||||
const ChannelHeader = makeAsyncComponent('ChannelHeader', lazy(() => import('components/channel_header')));
|
||||
@@ -28,6 +30,7 @@ type State = {
|
||||
url: string;
|
||||
focusedPostId?: string;
|
||||
deferredPostView: any;
|
||||
waitForLoader: boolean;
|
||||
};
|
||||
|
||||
export default class ChannelView extends React.PureComponent<Props, State> {
|
||||
@@ -77,6 +80,7 @@ export default class ChannelView extends React.PureComponent<Props, State> {
|
||||
channelId: props.channelId,
|
||||
focusedPostId: props.match.params.postid,
|
||||
deferredPostView: ChannelView.createDeferredPostView(),
|
||||
waitForLoader: false,
|
||||
};
|
||||
|
||||
this.channelViewRef = React.createRef();
|
||||
@@ -86,6 +90,10 @@ export default class ChannelView extends React.PureComponent<Props, State> {
|
||||
this.props.goToLastViewedChannel();
|
||||
};
|
||||
|
||||
onUpdateInputShowLoader = (v: boolean) => {
|
||||
this.setState({waitForLoader: v});
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
// TODO: debounce
|
||||
if (prevProps.channelId !== this.props.channelId && this.props.enableWebSocketEventScope) {
|
||||
@@ -151,6 +159,8 @@ export default class ChannelView extends React.PureComponent<Props, State> {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.missingChannelRole || this.state.waitForLoader) {
|
||||
createPost = <InputLoading updateWaitForLoader={this.onUpdateInputShowLoader}/>;
|
||||
} else {
|
||||
createPost = (
|
||||
<div
|
||||
|
||||
@@ -5,8 +5,11 @@ import {connect} from 'react-redux';
|
||||
import type {ConnectedProps} from 'react-redux';
|
||||
import {withRouter} from 'react-router-dom';
|
||||
|
||||
import {getCurrentChannel, getDirectTeammate} from 'mattermost-redux/selectors/entities/channels';
|
||||
import type {Channel} from '@mattermost/types/channels';
|
||||
|
||||
import {getCurrentChannel, getDirectTeammate, getMyChannelMembership} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getRoles} from 'mattermost-redux/selectors/entities/roles_helpers';
|
||||
import {getCurrentRelativeTeamUrl} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
@@ -24,6 +27,11 @@ function isDeactivatedChannel(state: GlobalState, channelId: string) {
|
||||
return Boolean(teammate && teammate.delete_at);
|
||||
}
|
||||
|
||||
function isMissingChannelRoles(state: GlobalState, channel?: Channel) {
|
||||
const channelRoles = channel ? getMyChannelMembership(state, channel.id)?.roles || '' : '';
|
||||
return !channelRoles.split(' ').some((v) => Boolean(getRoles(state)[v]));
|
||||
}
|
||||
|
||||
function mapStateToProps(state: GlobalState) {
|
||||
const channel = getCurrentChannel(state);
|
||||
|
||||
@@ -33,6 +41,8 @@ function mapStateToProps(state: GlobalState) {
|
||||
const enableOnboardingFlow = config.EnableOnboardingFlow === 'true';
|
||||
const enableWebSocketEventScope = config.FeatureFlagWebSocketEventScope === 'true';
|
||||
|
||||
const missingChannelRole = isMissingChannelRoles(state, channel);
|
||||
|
||||
return {
|
||||
channelId: channel ? channel.id : '',
|
||||
deactivatedChannel: channel ? isDeactivatedChannel(state, channel.id) : false,
|
||||
@@ -44,6 +54,7 @@ function mapStateToProps(state: GlobalState) {
|
||||
isFirstAdmin: isFirstAdmin(state),
|
||||
enableWebSocketEventScope,
|
||||
isChannelBookmarksEnabled: getIsChannelBookmarksEnabled(state),
|
||||
missingChannelRole,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
63
webapp/channels/src/components/channel_view/input_loading.tsx
Обычный файл
63
webapp/channels/src/components/channel_view/input_loading.tsx
Обычный файл
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
const onClickRefresh = () => {
|
||||
location.reload();
|
||||
};
|
||||
|
||||
const TIME_TO_SHOW = 5000;
|
||||
const TIME_TO_DISMISS = 2000;
|
||||
|
||||
type Props = {
|
||||
updateWaitForLoader: (v: boolean) => void;
|
||||
}
|
||||
|
||||
const InputLoading = ({
|
||||
updateWaitForLoader,
|
||||
}: Props) => {
|
||||
const [showMessage, setShowMessage] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let timeout = setTimeout(() => {
|
||||
setShowMessage(true);
|
||||
updateWaitForLoader(true);
|
||||
timeout = setTimeout(() => {
|
||||
updateWaitForLoader(false);
|
||||
}, TIME_TO_DISMISS);
|
||||
}, TIME_TO_SHOW);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
updateWaitForLoader(false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className='AdvancedTextEditor__skeleton'
|
||||
>
|
||||
{showMessage && (
|
||||
<>
|
||||
<FormattedMessage
|
||||
id='center_panel.input.cannot_load_component'
|
||||
defaultMessage='Something went wrong while loading the component. Please wait a moment, or try reloading the app.'
|
||||
/>
|
||||
<button
|
||||
className='btn btn-tertiary channel-archived__close-btn'
|
||||
onClick={onClickRefresh}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='center_panel.reloadPage'
|
||||
defaultMessage='Reload'
|
||||
/>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputLoading;
|
||||
@@ -3037,6 +3037,8 @@
|
||||
"center_panel.archived.closeChannel": "Close Channel",
|
||||
"center_panel.direct.closeDirectMessage": "Close Direct Message",
|
||||
"center_panel.direct.closeGroupMessage": "Close Group Message",
|
||||
"center_panel.input.cannot_load_component": "Something went wrong while loading the component. Please wait a moment, or try reloading the app.",
|
||||
"center_panel.reloadPage": "Reload",
|
||||
"change_url.endWithLetter": "URLs must end with a lowercase letter or number.",
|
||||
"change_url.helpText": "You can use lowercase letters, numbers, dashes, and underscores.",
|
||||
"change_url.invalidDirectMessage": "User IDs are not allowed in channel URLs.",
|
||||
|
||||
@@ -79,6 +79,7 @@ describe('identifyElementRegion', () => {
|
||||
[channel.id]: TestHelper.getChannelMembershipMock({
|
||||
channel_id: channel.id,
|
||||
user_id: user.id,
|
||||
roles: 'system_admin',
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
Ссылка в новой задаче
Block a user