MM-49862 - remove no longer needed webapp calls to action and pulsating dots (#22699)
* MM-49862 - remove no longer needed webapp calls to action and pulsating dots * fix snapshots * improve function logic based on pr comments * fix unit tests --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
9736304633
Коммит
6919761122
@@ -39,7 +39,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace disabled
|
||||
className="post-menu__item post-menu__item--active"
|
||||
id="center_actions_button_post_id_1"
|
||||
key="more-actions-button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
@@ -107,7 +106,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace enabled a
|
||||
className="post-menu__item post-menu__item--active"
|
||||
id="center_actions_button_post_id_1"
|
||||
key="more-actions-button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
@@ -194,7 +192,6 @@ exports[`components/actions_menu/ActionsMenu no actions - sysadmin - menu should
|
||||
className="post-menu__item post-menu__item--active"
|
||||
id="center_actions_button_post_id_1"
|
||||
key="more-actions-button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
|
||||
@@ -38,12 +38,7 @@ describe('components/actions_menu/ActionsMenu', () => {
|
||||
isSysAdmin: true,
|
||||
pluginMenuItems: [],
|
||||
post: TestHelper.getPostMock({id: 'post_id_1', is_pinned: false, type: '' as PostType}),
|
||||
showTutorialTip: false,
|
||||
components: {},
|
||||
handleOpenTip: jest.fn(),
|
||||
handleNextTip: jest.fn(),
|
||||
handleDismissTip: jest.fn(),
|
||||
showPulsatingDot: false,
|
||||
location: 'center',
|
||||
canOpenMarketplace: false,
|
||||
actions: {
|
||||
|
||||
@@ -17,7 +17,6 @@ import {AppCallResponseTypes} from 'mattermost-redux/constants/apps';
|
||||
import {HandleBindingClick, PostEphemeralCallResponseForPost, OpenAppsModal} from 'types/apps';
|
||||
import {Locations, Constants, ModalIdentifiers} from 'utils/constants';
|
||||
import Permissions from 'mattermost-redux/constants/permissions';
|
||||
import {ActionsTutorialTip} from 'components/actions_menu/actions_menu_tutorial_tip';
|
||||
import {ModalData} from 'types/actions';
|
||||
import MarketplaceModal, {OpenedFromType} from 'components/plugin_marketplace/marketplace_modal';
|
||||
import OverlayTrigger from 'components/overlay_trigger';
|
||||
@@ -44,11 +43,6 @@ export type Props = {
|
||||
pluginMenuItems?: PluginComponent[];
|
||||
post: Post;
|
||||
teamId: string;
|
||||
handleOpenTip: () => void;
|
||||
handleNextTip: (e: React.MouseEvent) => void;
|
||||
handleDismissTip: () => void;
|
||||
showPulsatingDot?: boolean;
|
||||
showTutorialTip: boolean;
|
||||
canOpenMarketplace: boolean;
|
||||
|
||||
/**
|
||||
@@ -236,14 +230,6 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
handleActionsIconClick = (e: React.MouseEvent) => {
|
||||
if (this.props.showPulsatingDot || this.props.showTutorialTip) {
|
||||
this.props.handleOpenTip();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
renderDivider = (suffix: string): React.ReactNode => {
|
||||
return (
|
||||
<li
|
||||
@@ -413,17 +399,8 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
||||
})}
|
||||
type='button'
|
||||
aria-expanded='false'
|
||||
onClick={this.handleActionsIconClick}
|
||||
>
|
||||
<i className={'icon icon-apps'}/>
|
||||
{this.props.showPulsatingDot &&
|
||||
<ActionsTutorialTip
|
||||
showTip={this.props.showTutorialTip}
|
||||
handleNext={this.props.handleNextTip}
|
||||
handleOpen={this.props.handleOpenTip}
|
||||
handleDismiss={this.props.handleDismissTip}
|
||||
/>
|
||||
}
|
||||
</button>
|
||||
</OverlayTrigger>
|
||||
<Menu
|
||||
|
||||
@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu returning empty ("")', () => {
|
||||
},
|
||||
appBindings: [],
|
||||
pluginMenuItems: [],
|
||||
handleOpenTip: jest.fn(),
|
||||
handleNextTip: jest.fn(),
|
||||
handleDismissTip: jest.fn(),
|
||||
showPulsatingDot: false,
|
||||
showTutorialTip: false,
|
||||
appsEnabled: false,
|
||||
isSysAdmin: true,
|
||||
canOpenMarketplace: false,
|
||||
|
||||
@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu on mobile view', () => {
|
||||
},
|
||||
appBindings: [],
|
||||
pluginMenuItems: [],
|
||||
handleOpenTip: jest.fn(),
|
||||
handleNextTip: jest.fn(),
|
||||
handleDismissTip: jest.fn(),
|
||||
showPulsatingDot: false,
|
||||
showTutorialTip: false,
|
||||
appsEnabled: false,
|
||||
isSysAdmin: true,
|
||||
canOpenMarketplace: false,
|
||||
|
||||
@@ -107,113 +107,6 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`components/dot_menu/DotMenu should match snapshot, hide "New" badge on forward post 1`] = `
|
||||
Object {
|
||||
"asFragment": [Function],
|
||||
"baseElement": <body>
|
||||
<div>
|
||||
<button
|
||||
aria-controls="CENTER_dropdown_post_id_1"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Actions"
|
||||
class="post-menu__item"
|
||||
data-testid="PostDotMenu-Button-post_id_1"
|
||||
id="CENTER_button_post_id_1"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</body>,
|
||||
"container": <div>
|
||||
<button
|
||||
aria-controls="CENTER_dropdown_post_id_1"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Actions"
|
||||
class="post-menu__item"
|
||||
data-testid="PostDotMenu-Button-post_id_1"
|
||||
id="CENTER_button_post_id_1"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>,
|
||||
"debug": [Function],
|
||||
"findAllByAltText": [Function],
|
||||
"findAllByDisplayValue": [Function],
|
||||
"findAllByLabelText": [Function],
|
||||
"findAllByPlaceholderText": [Function],
|
||||
"findAllByRole": [Function],
|
||||
"findAllByTestId": [Function],
|
||||
"findAllByText": [Function],
|
||||
"findAllByTitle": [Function],
|
||||
"findByAltText": [Function],
|
||||
"findByDisplayValue": [Function],
|
||||
"findByLabelText": [Function],
|
||||
"findByPlaceholderText": [Function],
|
||||
"findByRole": [Function],
|
||||
"findByTestId": [Function],
|
||||
"findByText": [Function],
|
||||
"findByTitle": [Function],
|
||||
"getAllByAltText": [Function],
|
||||
"getAllByDisplayValue": [Function],
|
||||
"getAllByLabelText": [Function],
|
||||
"getAllByPlaceholderText": [Function],
|
||||
"getAllByRole": [Function],
|
||||
"getAllByTestId": [Function],
|
||||
"getAllByText": [Function],
|
||||
"getAllByTitle": [Function],
|
||||
"getByAltText": [Function],
|
||||
"getByDisplayValue": [Function],
|
||||
"getByLabelText": [Function],
|
||||
"getByPlaceholderText": [Function],
|
||||
"getByRole": [Function],
|
||||
"getByTestId": [Function],
|
||||
"getByText": [Function],
|
||||
"getByTitle": [Function],
|
||||
"queryAllByAltText": [Function],
|
||||
"queryAllByDisplayValue": [Function],
|
||||
"queryAllByLabelText": [Function],
|
||||
"queryAllByPlaceholderText": [Function],
|
||||
"queryAllByRole": [Function],
|
||||
"queryAllByTestId": [Function],
|
||||
"queryAllByText": [Function],
|
||||
"queryAllByTitle": [Function],
|
||||
"queryByAltText": [Function],
|
||||
"queryByDisplayValue": [Function],
|
||||
"queryByLabelText": [Function],
|
||||
"queryByPlaceholderText": [Function],
|
||||
"queryByRole": [Function],
|
||||
"queryByTestId": [Function],
|
||||
"queryByText": [Function],
|
||||
"queryByTitle": [Function],
|
||||
"rerender": [Function],
|
||||
"unmount": [Function],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
|
||||
<Menu
|
||||
menu={
|
||||
@@ -483,110 +376,3 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
|
||||
/>
|
||||
</Menu>
|
||||
`;
|
||||
|
||||
exports[`components/dot_menu/DotMenu should match snapshot, show "New" badge on forward post 1`] = `
|
||||
Object {
|
||||
"asFragment": [Function],
|
||||
"baseElement": <body>
|
||||
<div>
|
||||
<button
|
||||
aria-controls="CENTER_dropdown_post_id_1"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Actions"
|
||||
class="post-menu__item"
|
||||
data-testid="PostDotMenu-Button-post_id_1"
|
||||
id="CENTER_button_post_id_1"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</body>,
|
||||
"container": <div>
|
||||
<button
|
||||
aria-controls="CENTER_dropdown_post_id_1"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Actions"
|
||||
class="post-menu__item"
|
||||
data-testid="PostDotMenu-Button-post_id_1"
|
||||
id="CENTER_button_post_id_1"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>,
|
||||
"debug": [Function],
|
||||
"findAllByAltText": [Function],
|
||||
"findAllByDisplayValue": [Function],
|
||||
"findAllByLabelText": [Function],
|
||||
"findAllByPlaceholderText": [Function],
|
||||
"findAllByRole": [Function],
|
||||
"findAllByTestId": [Function],
|
||||
"findAllByText": [Function],
|
||||
"findAllByTitle": [Function],
|
||||
"findByAltText": [Function],
|
||||
"findByDisplayValue": [Function],
|
||||
"findByLabelText": [Function],
|
||||
"findByPlaceholderText": [Function],
|
||||
"findByRole": [Function],
|
||||
"findByTestId": [Function],
|
||||
"findByText": [Function],
|
||||
"findByTitle": [Function],
|
||||
"getAllByAltText": [Function],
|
||||
"getAllByDisplayValue": [Function],
|
||||
"getAllByLabelText": [Function],
|
||||
"getAllByPlaceholderText": [Function],
|
||||
"getAllByRole": [Function],
|
||||
"getAllByTestId": [Function],
|
||||
"getAllByText": [Function],
|
||||
"getAllByTitle": [Function],
|
||||
"getByAltText": [Function],
|
||||
"getByDisplayValue": [Function],
|
||||
"getByLabelText": [Function],
|
||||
"getByPlaceholderText": [Function],
|
||||
"getByRole": [Function],
|
||||
"getByTestId": [Function],
|
||||
"getByText": [Function],
|
||||
"getByTitle": [Function],
|
||||
"queryAllByAltText": [Function],
|
||||
"queryAllByDisplayValue": [Function],
|
||||
"queryAllByLabelText": [Function],
|
||||
"queryAllByPlaceholderText": [Function],
|
||||
"queryAllByRole": [Function],
|
||||
"queryAllByTestId": [Function],
|
||||
"queryAllByText": [Function],
|
||||
"queryAllByTitle": [Function],
|
||||
"queryByAltText": [Function],
|
||||
"queryByDisplayValue": [Function],
|
||||
"queryByLabelText": [Function],
|
||||
"queryByPlaceholderText": [Function],
|
||||
"queryByRole": [Function],
|
||||
"queryByTestId": [Function],
|
||||
"queryByText": [Function],
|
||||
"queryByTitle": [Function],
|
||||
"rerender": [Function],
|
||||
"unmount": [Function],
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -146,7 +146,6 @@ describe('components/dot_menu/DotMenu', () => {
|
||||
threadReplyCount: 0,
|
||||
userId: 'user_id_1',
|
||||
isMilitaryTime: false,
|
||||
showForwardPostNewLabel: false,
|
||||
};
|
||||
|
||||
test('should match snapshot, on Center', () => {
|
||||
@@ -181,32 +180,6 @@ describe('components/dot_menu/DotMenu', () => {
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot, show "New" badge on forward post', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
showForwardPostNewLabel: true,
|
||||
};
|
||||
const wrapper = renderWithIntlAndStore(
|
||||
<DotMenu {...props}/>,
|
||||
initialState,
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot, hide "New" badge on forward post', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
showForwardPostNewLabel: false,
|
||||
};
|
||||
const wrapper = renderWithIntlAndStore(
|
||||
<DotMenu {...props}/>,
|
||||
initialState,
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should show mark as unread when channel is not archived', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
|
||||
import Permissions from 'mattermost-redux/constants/permissions';
|
||||
|
||||
import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS, Preferences} from 'utils/constants';
|
||||
import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS} from 'utils/constants';
|
||||
import DeletePostModal from 'components/delete_post_modal';
|
||||
import DelayedAction from 'utils/delayed_action';
|
||||
import * as PostUtils from 'utils/post_utils';
|
||||
@@ -33,12 +33,10 @@ import * as Menu from 'components/menu';
|
||||
import * as Utils from 'utils/utils';
|
||||
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';
|
||||
import {ModalData} from 'types/actions';
|
||||
import {PluginComponent} from 'types/store/plugins';
|
||||
|
||||
import {UserThread} from '@mattermost/types/threads';
|
||||
import {Post} from '@mattermost/types/posts';
|
||||
import ForwardPostModal from '../forward_post_modal';
|
||||
import Tag from '../widgets/tag/tag';
|
||||
|
||||
import {ChangeEvent, trackDotMenuEvent} from './utils';
|
||||
|
||||
@@ -70,20 +68,11 @@ type Props = {
|
||||
postEditTimeLimit?: string; // TechDebt: Made non-mandatory while converting to typescript
|
||||
enableEmojiPicker?: boolean; // TechDebt: Made non-mandatory while converting to typescript
|
||||
channelIsArchived?: boolean; // TechDebt: Made non-mandatory while converting to typescript
|
||||
currentTeamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript
|
||||
teamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript
|
||||
isMobileView: boolean;
|
||||
showForwardPostNewLabel: boolean;
|
||||
timezone?: string;
|
||||
isMilitaryTime: boolean;
|
||||
|
||||
/**
|
||||
* Components for overriding provided by plugins
|
||||
*/
|
||||
components: {
|
||||
[componentName: string]: PluginComponent[];
|
||||
};
|
||||
|
||||
actions: {
|
||||
|
||||
/**
|
||||
@@ -292,9 +281,6 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
||||
},
|
||||
};
|
||||
|
||||
if (this.props.showForwardPostNewLabel) {
|
||||
this.props.actions.setGlobalItem(Preferences.FORWARD_POST_VIEWED, false);
|
||||
}
|
||||
this.props.actions.openModal(forwardPostModalData);
|
||||
}
|
||||
|
||||
@@ -441,15 +427,6 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
||||
id='forward_post_button.label'
|
||||
defaultMessage='Forward'
|
||||
/>
|
||||
{this.props.showForwardPostNewLabel && (
|
||||
<Tag
|
||||
variant='success'
|
||||
text={formatMessage({
|
||||
id: 'tag.default.new',
|
||||
defaultMessage: 'NEW',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -519,12 +496,12 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
||||
class: classNames('post-menu__item', {
|
||||
'post-menu__item--active': this.props.isMenuOpen,
|
||||
}),
|
||||
'aria-label': this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}),
|
||||
'aria-label': formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}),
|
||||
children: <DotsHorizontalIcon size={16}/>,
|
||||
}}
|
||||
menu={{
|
||||
id: `${this.props.location}_dropdown_${this.props.post.id}`,
|
||||
'aria-label': this.props.intl.formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}),
|
||||
'aria-label': formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}),
|
||||
onKeyDown: this.onShortcutKeyDown,
|
||||
width: '264px',
|
||||
onToggle: this.handleMenuToggle,
|
||||
@@ -532,7 +509,7 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
||||
}}
|
||||
menuButtonTooltip={{
|
||||
id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`,
|
||||
text: this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}),
|
||||
text: formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}),
|
||||
class: 'hidden-xs',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu returning empty ("")', () => {
|
||||
threadId: 'post_id_1',
|
||||
userId: 'user_id_1',
|
||||
isMilitaryTime: false,
|
||||
showForwardPostNewLabel: false,
|
||||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
|
||||
@@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu on mobile view', () => {
|
||||
threadId: 'post_id_1',
|
||||
userId: 'user_id_1',
|
||||
isMilitaryTime: false,
|
||||
showForwardPostNewLabel: false,
|
||||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
|
||||
@@ -44,7 +44,6 @@ import {matchUserMentionTriggersWithMessageMentions} from 'utils/post_utils';
|
||||
|
||||
import {Post} from '@mattermost/types/posts';
|
||||
import {setGlobalItem} from '../../actions/storage';
|
||||
import {getGlobalItem} from '../../selectors/storage';
|
||||
|
||||
import DotMenu from './dot_menu';
|
||||
|
||||
@@ -110,8 +109,6 @@ function makeMapStateToProps() {
|
||||
}
|
||||
}
|
||||
|
||||
const showForwardPostNewLabel = getGlobalItem(state, Preferences.FORWARD_POST_VIEWED, true);
|
||||
|
||||
return {
|
||||
channelIsArchived: isArchivedChannel(channel),
|
||||
components: state.plugins.components,
|
||||
@@ -129,7 +126,6 @@ function makeMapStateToProps() {
|
||||
isCollapsedThreadsEnabled: collapsedThreads,
|
||||
threadReplyCount,
|
||||
isMobileView: getIsMobileView(state),
|
||||
showForwardPostNewLabel,
|
||||
timezone: getCurrentUserTimezone(state),
|
||||
isMilitaryTime,
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import {connect, ConnectedProps} from 'react-redux';
|
||||
import {AnyAction, bindActionCreators, Dispatch} from 'redux';
|
||||
|
||||
import {showActionsDropdownPulsatingDot} from 'selectors/actions_menu';
|
||||
import {setActionsMenuInitialisationState} from 'mattermost-redux/actions/preferences';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled, UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
||||
@@ -13,7 +12,6 @@ import {
|
||||
get,
|
||||
getBool,
|
||||
isCollapsedThreadsEnabled,
|
||||
onboardingTourTipsEnabled,
|
||||
} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentTeam, getCurrentTeamId, getTeam, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
|
||||
@@ -129,8 +127,7 @@ function makeMapStateToProps() {
|
||||
const user = getUser(state, post.user_id);
|
||||
const isBot = Boolean(user && user.is_bot);
|
||||
const highlightedPostId = getHighlightedPostId(state);
|
||||
const showActionsMenuPulsatingDot = showActionsDropdownPulsatingDot(state);
|
||||
const tourTipsEnabled = onboardingTourTipsEnabled(state);
|
||||
|
||||
const selectedCard = getSelectedPostCard(state);
|
||||
|
||||
let emojis: Emoji[] = [];
|
||||
@@ -203,8 +200,7 @@ function makeMapStateToProps() {
|
||||
compactDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
||||
colorizeUsernames: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLORIZE_USERNAMES, Preferences.COLORIZE_USERNAMES_DEFAULT) === 'true',
|
||||
shouldShowActionsMenu: shouldShowActionsMenu(state, post),
|
||||
showActionsMenuPulsatingDot,
|
||||
tourTipsEnabled,
|
||||
|
||||
shortcutReactToLastPostEmittedFrom,
|
||||
isBot,
|
||||
collapsedThreadsEnabled: isCollapsedThreadsEnabled(state),
|
||||
|
||||
@@ -114,8 +114,6 @@ export type Props = {
|
||||
isPostAcknowledgementsEnabled: boolean;
|
||||
isPostPriorityEnabled: boolean;
|
||||
isCardOpen?: boolean;
|
||||
shouldShowDotMenu: boolean;
|
||||
tourTipsEnabled: boolean;
|
||||
};
|
||||
|
||||
const PostComponent = (props: Props): JSX.Element => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, {ReactNode, useEffect, useRef, useState} from 'react';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import {Posts, Preferences} from 'mattermost-redux/constants/index';
|
||||
import {Posts} from 'mattermost-redux/constants/index';
|
||||
import {isPostEphemeral} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
import {Locations} from 'utils/constants';
|
||||
@@ -34,8 +34,6 @@ type Props = {
|
||||
handleDropdownOpened?: (e: boolean) => void;
|
||||
collapsedThreadsEnabled?: boolean;
|
||||
shouldShowActionsMenu?: boolean;
|
||||
showActionsMenuPulsatingDot?: boolean;
|
||||
tourTipsEnabled: boolean;
|
||||
oneClickReactionsEnabled?: boolean;
|
||||
recentEmojis: Emoji[];
|
||||
isExpanded?: boolean;
|
||||
@@ -51,7 +49,6 @@ type Props = {
|
||||
shortcutReactToLastPostEmittedFrom?: string;
|
||||
isPostHeaderVisible?: boolean | null;
|
||||
isPostBeingEdited?: boolean;
|
||||
shouldShowDotMenu: boolean;
|
||||
actions: {
|
||||
emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void;
|
||||
};
|
||||
@@ -63,7 +60,6 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||
const [showDotMenu, setShowDotMenu] = useState(false);
|
||||
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
||||
const [showActionTip, setShowActionTip] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.isLastPost &&
|
||||
@@ -80,8 +76,6 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
isReadOnly,
|
||||
post,
|
||||
oneClickReactionsEnabled,
|
||||
showActionsMenuPulsatingDot,
|
||||
tourTipsEnabled,
|
||||
isMobileView,
|
||||
} = props;
|
||||
|
||||
@@ -102,34 +96,14 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
};
|
||||
|
||||
const handleActionsMenuOpened = (open: boolean) => {
|
||||
if (tourTipsEnabled && showActionsMenuPulsatingDot) {
|
||||
setShowActionTip(true);
|
||||
return;
|
||||
}
|
||||
setShowActionsMenu(open);
|
||||
props.handleDropdownOpened!(open);
|
||||
};
|
||||
|
||||
const handleActionsMenuTipOpened = () => {
|
||||
setShowActionTip(true);
|
||||
props.handleDropdownOpened!(true);
|
||||
};
|
||||
|
||||
const handleActionsMenuGotItClick = () => {
|
||||
props.setActionsMenuInitialisationState?.(({[Preferences.ACTIONS_MENU_VIEWED]: true}));
|
||||
setShowActionTip(false);
|
||||
props.handleDropdownOpened!(false);
|
||||
};
|
||||
|
||||
const handleTipDismissed = () => {
|
||||
setShowActionTip(false);
|
||||
props.handleDropdownOpened!(false);
|
||||
};
|
||||
|
||||
const getDotMenuRef = () => dotMenuRef.current;
|
||||
|
||||
const isPostDeleted = post && post.state === Posts.POST_DELETED;
|
||||
const hoverLocal = props.hover || showEmojiPicker || showDotMenu || showActionsMenu || showActionTip;
|
||||
const hoverLocal = props.hover || showEmojiPicker || showDotMenu || showActionsMenu;
|
||||
const showCommentIcon = isFromAutoResponder || (!systemMessage && (isMobileView ||
|
||||
hoverLocal || (!post.root_id && Boolean(props.hasReplies)) ||
|
||||
props.isFirstReply) && props.location === Locations.CENTER);
|
||||
@@ -197,11 +171,6 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
location={props.location}
|
||||
handleDropdownOpened={handleActionsMenuOpened}
|
||||
isMenuOpen={showActionsMenu}
|
||||
showPulsatingDot={tourTipsEnabled && showActionsMenuPulsatingDot}
|
||||
showTutorialTip={tourTipsEnabled && showActionTip}
|
||||
handleOpenTip={handleActionsMenuTipOpened}
|
||||
handleNextTip={handleActionsMenuGotItClick}
|
||||
handleDismissTip={handleTipDismissed}
|
||||
/>
|
||||
);
|
||||
const dotMenu = (
|
||||
@@ -231,7 +200,7 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
} else if (isPostDeleted || !props.shouldShowDotMenu) {
|
||||
} else if (isPostDeleted) {
|
||||
options = null;
|
||||
} else if (props.location === Locations.SEARCH) {
|
||||
const hasCRTFooter = props.collapsedThreadsEnabled && !post.root_id && (post.reply_count > 0 || post.is_following);
|
||||
|
||||
@@ -27,7 +27,6 @@ type Props = {
|
||||
previousPostId: string;
|
||||
teamId: string;
|
||||
timestampProps?: Partial<TimestampProps>;
|
||||
lastPost: Post;
|
||||
};
|
||||
|
||||
function noop() {}
|
||||
|
||||
@@ -403,7 +403,6 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
previousPostId={getPreviousPostId(data, index)}
|
||||
teamId={this.props.teamId}
|
||||
timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined}
|
||||
lastPost={this.props.lastPost}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import {makeGetCustomStatus, getRecentCustomStatuses, isCustomStatusEnabled, sho
|
||||
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
import {CustomStatusDuration} from '@mattermost/types/users';
|
||||
import {addTimeToTimestamp, TimeInformation} from 'utils/utils';
|
||||
|
||||
jest.mock('mattermost-redux/selectors/entities/users');
|
||||
jest.mock('mattermost-redux/selectors/entities/general');
|
||||
@@ -86,6 +87,7 @@ describe('isCustomStatusEnabled', () => {
|
||||
});
|
||||
|
||||
describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton', () => {
|
||||
const user = TestHelper.getUserMock();
|
||||
const preference = {
|
||||
myPreference: {
|
||||
value: '',
|
||||
@@ -104,4 +106,31 @@ describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton',
|
||||
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
|
||||
expect(showPostHeaderUpdateStatusButton(store.getState())).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return false if user was created less than seven days before from today', async () => {
|
||||
const store = await configureStore();
|
||||
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
|
||||
const todayTimestamp = new Date().getTime();
|
||||
|
||||
// set the user create date to 6 days in the past from today
|
||||
const todayMinusSixDays = addTimeToTimestamp(todayTimestamp, TimeInformation.DAYS, 6, TimeInformation.PAST);
|
||||
const newUser = {...user, create_at: todayMinusSixDays};
|
||||
newUser.props.customStatus = JSON.stringify(customStatus);
|
||||
(UserSelectors.getCurrentUser as jest.Mock).mockReturnValue(newUser);
|
||||
expect(showStatusDropdownPulsatingDot(store.getState())).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return true if user was created more than seven days before from today', async () => {
|
||||
const store = await configureStore();
|
||||
preference.myPreference.value = JSON.stringify({[Preferences.CUSTOM_STATUS_MODAL_VIEWED]: false});
|
||||
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
|
||||
const todayTimestamp = new Date().getTime();
|
||||
|
||||
// set the user create date to 8 days in the past from today
|
||||
const todayMinusEightDays = addTimeToTimestamp(todayTimestamp, TimeInformation.DAYS, 8, TimeInformation.PAST);
|
||||
const newUser = {...user, create_at: todayMinusEightDays};
|
||||
newUser.props.customStatus = JSON.stringify(customStatus);
|
||||
(UserSelectors.getCurrentUser as jest.Mock).mockReturnValue(newUser);
|
||||
expect(showStatusDropdownPulsatingDot(store.getState())).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,8 @@ import {get} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {Preferences} from 'mattermost-redux/constants';
|
||||
import {CustomStatusDuration, UserCustomStatus} from '@mattermost/types/users';
|
||||
|
||||
import {isDateWithinDaysRange, TimeInformation} from 'utils/utils';
|
||||
|
||||
import {GlobalState} from 'types/store';
|
||||
import {getCurrentUserTimezone} from 'selectors/general';
|
||||
import {getCurrentMomentForTimezone} from 'utils/timezone';
|
||||
@@ -56,9 +58,12 @@ export function isCustomStatusEnabled(state: GlobalState) {
|
||||
}
|
||||
|
||||
function showCustomStatusPulsatingDotAndPostHeader(state: GlobalState) {
|
||||
// only show this for users after the first seven days
|
||||
const currentUser = getCurrentUser(state);
|
||||
const hasUserCreationMoreThanSevenDays = isDateWithinDaysRange(currentUser?.create_at, 7, TimeInformation.FUTURE);
|
||||
const customStatusTutorialState = get(state, Preferences.CATEGORY_CUSTOM_STATUS, Preferences.NAME_CUSTOM_STATUS_TUTORIAL_STATE);
|
||||
const modalAlreadyViewed = customStatusTutorialState && JSON.parse(customStatusTutorialState)[Preferences.CUSTOM_STATUS_MODAL_VIEWED];
|
||||
return !modalAlreadyViewed;
|
||||
return !modalAlreadyViewed && hasUserCreationMoreThanSevenDays;
|
||||
}
|
||||
|
||||
export function showStatusDropdownPulsatingDot(state: GlobalState) {
|
||||
|
||||
@@ -90,6 +90,23 @@ const CLICKABLE_ELEMENTS = [
|
||||
'audio',
|
||||
'video',
|
||||
];
|
||||
const MS_PER_SECOND = 1000;
|
||||
const MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
||||
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
||||
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
||||
|
||||
export enum TimeInformation {
|
||||
MILLISECONDS = 'm',
|
||||
SECONDS = 's',
|
||||
MINUTES = 'x',
|
||||
HOURS = 'h',
|
||||
DAYS = 'd',
|
||||
FUTURE = 'f',
|
||||
PAST = 'p'
|
||||
}
|
||||
|
||||
export type TimeUnit = Exclude<TimeInformation, TimeInformation.FUTURE | TimeInformation.PAST>;
|
||||
export type TimeDirection = TimeInformation.FUTURE | TimeInformation.PAST;
|
||||
|
||||
export function isMac() {
|
||||
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||
@@ -256,7 +273,6 @@ export function getTimestamp(): number {
|
||||
}
|
||||
|
||||
export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number {
|
||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
const futureDate = new Date(timestamp as number);
|
||||
const utcFuture = Date.UTC(futureDate.getFullYear(), futureDate.getMonth(), futureDate.getDate());
|
||||
const today = new Date();
|
||||
@@ -265,6 +281,39 @@ export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number
|
||||
return Math.floor((utcFuture - utcToday) / MS_PER_DAY);
|
||||
}
|
||||
|
||||
export function addTimeToTimestamp(timestamp: number, type: TimeUnit, diff: number, timeline: TimeDirection) {
|
||||
let modifier = 1;
|
||||
switch (type) {
|
||||
case TimeInformation.SECONDS:
|
||||
modifier = MS_PER_SECOND;
|
||||
break;
|
||||
case TimeInformation.MINUTES:
|
||||
modifier = MS_PER_MINUTE;
|
||||
break;
|
||||
case TimeInformation.HOURS:
|
||||
modifier = MS_PER_HOUR;
|
||||
break;
|
||||
case TimeInformation.DAYS:
|
||||
modifier = MS_PER_DAY;
|
||||
break;
|
||||
}
|
||||
|
||||
return timeline === TimeInformation.FUTURE ? timestamp + (diff * modifier) : timestamp - (diff * modifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if a date is in a particular given range of days from today
|
||||
* @param timestamp date you want to check is in the range of the provided number of days from today
|
||||
* @param days number of days you want to check your date against to
|
||||
* @param timeline 'f' represents future, 'p' represents past
|
||||
* @returns boolean, true if your date is in the range of the provided number of days
|
||||
*/
|
||||
export function isDateWithinDaysRange(timestamp: number, days: number, timeline: TimeDirection): boolean {
|
||||
const today = new Date().getTime();
|
||||
const daysSince = Math.round((today - timestamp) / MS_PER_DAY);
|
||||
return timeline === TimeInformation.PAST ? daysSince <= days : daysSince >= days;
|
||||
}
|
||||
|
||||
export function getLocaleDateFromUTC(timestamp: number, format = 'YYYY/MM/DD HH:mm:ss', userTimezone = '') {
|
||||
if (!timestamp) {
|
||||
return moment.now();
|
||||
|
||||
Ссылка в новой задаче
Block a user