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"
|
className="post-menu__item post-menu__item--active"
|
||||||
id="center_actions_button_post_id_1"
|
id="center_actions_button_post_id_1"
|
||||||
key="more-actions-button"
|
key="more-actions-button"
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@@ -107,7 +106,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace enabled a
|
|||||||
className="post-menu__item post-menu__item--active"
|
className="post-menu__item post-menu__item--active"
|
||||||
id="center_actions_button_post_id_1"
|
id="center_actions_button_post_id_1"
|
||||||
key="more-actions-button"
|
key="more-actions-button"
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@@ -194,7 +192,6 @@ exports[`components/actions_menu/ActionsMenu no actions - sysadmin - menu should
|
|||||||
className="post-menu__item post-menu__item--active"
|
className="post-menu__item post-menu__item--active"
|
||||||
id="center_actions_button_post_id_1"
|
id="center_actions_button_post_id_1"
|
||||||
key="more-actions-button"
|
key="more-actions-button"
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
|
|||||||
@@ -38,12 +38,7 @@ describe('components/actions_menu/ActionsMenu', () => {
|
|||||||
isSysAdmin: true,
|
isSysAdmin: true,
|
||||||
pluginMenuItems: [],
|
pluginMenuItems: [],
|
||||||
post: TestHelper.getPostMock({id: 'post_id_1', is_pinned: false, type: '' as PostType}),
|
post: TestHelper.getPostMock({id: 'post_id_1', is_pinned: false, type: '' as PostType}),
|
||||||
showTutorialTip: false,
|
|
||||||
components: {},
|
components: {},
|
||||||
handleOpenTip: jest.fn(),
|
|
||||||
handleNextTip: jest.fn(),
|
|
||||||
handleDismissTip: jest.fn(),
|
|
||||||
showPulsatingDot: false,
|
|
||||||
location: 'center',
|
location: 'center',
|
||||||
canOpenMarketplace: false,
|
canOpenMarketplace: false,
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {AppCallResponseTypes} from 'mattermost-redux/constants/apps';
|
|||||||
import {HandleBindingClick, PostEphemeralCallResponseForPost, OpenAppsModal} from 'types/apps';
|
import {HandleBindingClick, PostEphemeralCallResponseForPost, OpenAppsModal} from 'types/apps';
|
||||||
import {Locations, Constants, ModalIdentifiers} from 'utils/constants';
|
import {Locations, Constants, ModalIdentifiers} from 'utils/constants';
|
||||||
import Permissions from 'mattermost-redux/constants/permissions';
|
import Permissions from 'mattermost-redux/constants/permissions';
|
||||||
import {ActionsTutorialTip} from 'components/actions_menu/actions_menu_tutorial_tip';
|
|
||||||
import {ModalData} from 'types/actions';
|
import {ModalData} from 'types/actions';
|
||||||
import MarketplaceModal, {OpenedFromType} from 'components/plugin_marketplace/marketplace_modal';
|
import MarketplaceModal, {OpenedFromType} from 'components/plugin_marketplace/marketplace_modal';
|
||||||
import OverlayTrigger from 'components/overlay_trigger';
|
import OverlayTrigger from 'components/overlay_trigger';
|
||||||
@@ -44,11 +43,6 @@ export type Props = {
|
|||||||
pluginMenuItems?: PluginComponent[];
|
pluginMenuItems?: PluginComponent[];
|
||||||
post: Post;
|
post: Post;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
handleOpenTip: () => void;
|
|
||||||
handleNextTip: (e: React.MouseEvent) => void;
|
|
||||||
handleDismissTip: () => void;
|
|
||||||
showPulsatingDot?: boolean;
|
|
||||||
showTutorialTip: boolean;
|
|
||||||
canOpenMarketplace: 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 => {
|
renderDivider = (suffix: string): React.ReactNode => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
@@ -413,17 +399,8 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
|||||||
})}
|
})}
|
||||||
type='button'
|
type='button'
|
||||||
aria-expanded='false'
|
aria-expanded='false'
|
||||||
onClick={this.handleActionsIconClick}
|
|
||||||
>
|
>
|
||||||
<i className={'icon icon-apps'}/>
|
<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>
|
</button>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Menu
|
<Menu
|
||||||
|
|||||||
@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu returning empty ("")', () => {
|
|||||||
},
|
},
|
||||||
appBindings: [],
|
appBindings: [],
|
||||||
pluginMenuItems: [],
|
pluginMenuItems: [],
|
||||||
handleOpenTip: jest.fn(),
|
|
||||||
handleNextTip: jest.fn(),
|
|
||||||
handleDismissTip: jest.fn(),
|
|
||||||
showPulsatingDot: false,
|
|
||||||
showTutorialTip: false,
|
|
||||||
appsEnabled: false,
|
appsEnabled: false,
|
||||||
isSysAdmin: true,
|
isSysAdmin: true,
|
||||||
canOpenMarketplace: false,
|
canOpenMarketplace: false,
|
||||||
|
|||||||
@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu on mobile view', () => {
|
|||||||
},
|
},
|
||||||
appBindings: [],
|
appBindings: [],
|
||||||
pluginMenuItems: [],
|
pluginMenuItems: [],
|
||||||
handleOpenTip: jest.fn(),
|
|
||||||
handleNextTip: jest.fn(),
|
|
||||||
handleDismissTip: jest.fn(),
|
|
||||||
showPulsatingDot: false,
|
|
||||||
showTutorialTip: false,
|
|
||||||
appsEnabled: false,
|
appsEnabled: false,
|
||||||
isSysAdmin: true,
|
isSysAdmin: true,
|
||||||
canOpenMarketplace: false,
|
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`] = `
|
exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
|
||||||
<Menu
|
<Menu
|
||||||
menu={
|
menu={
|
||||||
@@ -483,110 +376,3 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
|
|||||||
/>
|
/>
|
||||||
</Menu>
|
</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,
|
threadReplyCount: 0,
|
||||||
userId: 'user_id_1',
|
userId: 'user_id_1',
|
||||||
isMilitaryTime: false,
|
isMilitaryTime: false,
|
||||||
showForwardPostNewLabel: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should match snapshot, on Center', () => {
|
test('should match snapshot, on Center', () => {
|
||||||
@@ -181,32 +180,6 @@ describe('components/dot_menu/DotMenu', () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
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', () => {
|
test('should show mark as unread when channel is not archived', () => {
|
||||||
const props = {
|
const props = {
|
||||||
...baseProps,
|
...baseProps,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
|
|
||||||
import Permissions from 'mattermost-redux/constants/permissions';
|
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 DeletePostModal from 'components/delete_post_modal';
|
||||||
import DelayedAction from 'utils/delayed_action';
|
import DelayedAction from 'utils/delayed_action';
|
||||||
import * as PostUtils from 'utils/post_utils';
|
import * as PostUtils from 'utils/post_utils';
|
||||||
@@ -33,12 +33,10 @@ import * as Menu from 'components/menu';
|
|||||||
import * as Utils from 'utils/utils';
|
import * as Utils from 'utils/utils';
|
||||||
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';
|
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';
|
||||||
import {ModalData} from 'types/actions';
|
import {ModalData} from 'types/actions';
|
||||||
import {PluginComponent} from 'types/store/plugins';
|
|
||||||
|
|
||||||
import {UserThread} from '@mattermost/types/threads';
|
import {UserThread} from '@mattermost/types/threads';
|
||||||
import {Post} from '@mattermost/types/posts';
|
import {Post} from '@mattermost/types/posts';
|
||||||
import ForwardPostModal from '../forward_post_modal';
|
import ForwardPostModal from '../forward_post_modal';
|
||||||
import Tag from '../widgets/tag/tag';
|
|
||||||
|
|
||||||
import {ChangeEvent, trackDotMenuEvent} from './utils';
|
import {ChangeEvent, trackDotMenuEvent} from './utils';
|
||||||
|
|
||||||
@@ -70,20 +68,11 @@ type Props = {
|
|||||||
postEditTimeLimit?: string; // TechDebt: Made non-mandatory while converting to typescript
|
postEditTimeLimit?: string; // TechDebt: Made non-mandatory while converting to typescript
|
||||||
enableEmojiPicker?: boolean; // 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
|
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
|
teamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript
|
||||||
isMobileView: boolean;
|
isMobileView: boolean;
|
||||||
showForwardPostNewLabel: boolean;
|
|
||||||
timezone?: string;
|
timezone?: string;
|
||||||
isMilitaryTime: boolean;
|
isMilitaryTime: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* Components for overriding provided by plugins
|
|
||||||
*/
|
|
||||||
components: {
|
|
||||||
[componentName: string]: PluginComponent[];
|
|
||||||
};
|
|
||||||
|
|
||||||
actions: {
|
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);
|
this.props.actions.openModal(forwardPostModalData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,15 +427,6 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
|||||||
id='forward_post_button.label'
|
id='forward_post_button.label'
|
||||||
defaultMessage='Forward'
|
defaultMessage='Forward'
|
||||||
/>
|
/>
|
||||||
{this.props.showForwardPostNewLabel && (
|
|
||||||
<Tag
|
|
||||||
variant='success'
|
|
||||||
text={formatMessage({
|
|
||||||
id: 'tag.default.new',
|
|
||||||
defaultMessage: 'NEW',
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -519,12 +496,12 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
|||||||
class: classNames('post-menu__item', {
|
class: classNames('post-menu__item', {
|
||||||
'post-menu__item--active': this.props.isMenuOpen,
|
'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}/>,
|
children: <DotsHorizontalIcon size={16}/>,
|
||||||
}}
|
}}
|
||||||
menu={{
|
menu={{
|
||||||
id: `${this.props.location}_dropdown_${this.props.post.id}`,
|
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,
|
onKeyDown: this.onShortcutKeyDown,
|
||||||
width: '264px',
|
width: '264px',
|
||||||
onToggle: this.handleMenuToggle,
|
onToggle: this.handleMenuToggle,
|
||||||
@@ -532,7 +509,7 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
|||||||
}}
|
}}
|
||||||
menuButtonTooltip={{
|
menuButtonTooltip={{
|
||||||
id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`,
|
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',
|
class: 'hidden-xs',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu returning empty ("")', () => {
|
|||||||
threadId: 'post_id_1',
|
threadId: 'post_id_1',
|
||||||
userId: 'user_id_1',
|
userId: 'user_id_1',
|
||||||
isMilitaryTime: false,
|
isMilitaryTime: false,
|
||||||
showForwardPostNewLabel: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = shallow(
|
const wrapper = shallow(
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu on mobile view', () => {
|
|||||||
threadId: 'post_id_1',
|
threadId: 'post_id_1',
|
||||||
userId: 'user_id_1',
|
userId: 'user_id_1',
|
||||||
isMilitaryTime: false,
|
isMilitaryTime: false,
|
||||||
showForwardPostNewLabel: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = shallow(
|
const wrapper = shallow(
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import {matchUserMentionTriggersWithMessageMentions} from 'utils/post_utils';
|
|||||||
|
|
||||||
import {Post} from '@mattermost/types/posts';
|
import {Post} from '@mattermost/types/posts';
|
||||||
import {setGlobalItem} from '../../actions/storage';
|
import {setGlobalItem} from '../../actions/storage';
|
||||||
import {getGlobalItem} from '../../selectors/storage';
|
|
||||||
|
|
||||||
import DotMenu from './dot_menu';
|
import DotMenu from './dot_menu';
|
||||||
|
|
||||||
@@ -110,8 +109,6 @@ function makeMapStateToProps() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showForwardPostNewLabel = getGlobalItem(state, Preferences.FORWARD_POST_VIEWED, true);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channelIsArchived: isArchivedChannel(channel),
|
channelIsArchived: isArchivedChannel(channel),
|
||||||
components: state.plugins.components,
|
components: state.plugins.components,
|
||||||
@@ -129,7 +126,6 @@ function makeMapStateToProps() {
|
|||||||
isCollapsedThreadsEnabled: collapsedThreads,
|
isCollapsedThreadsEnabled: collapsedThreads,
|
||||||
threadReplyCount,
|
threadReplyCount,
|
||||||
isMobileView: getIsMobileView(state),
|
isMobileView: getIsMobileView(state),
|
||||||
showForwardPostNewLabel,
|
|
||||||
timezone: getCurrentUserTimezone(state),
|
timezone: getCurrentUserTimezone(state),
|
||||||
isMilitaryTime,
|
isMilitaryTime,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
import {connect, ConnectedProps} from 'react-redux';
|
import {connect, ConnectedProps} from 'react-redux';
|
||||||
import {AnyAction, bindActionCreators, Dispatch} from 'redux';
|
import {AnyAction, bindActionCreators, Dispatch} from 'redux';
|
||||||
|
|
||||||
import {showActionsDropdownPulsatingDot} from 'selectors/actions_menu';
|
|
||||||
import {setActionsMenuInitialisationState} from 'mattermost-redux/actions/preferences';
|
import {setActionsMenuInitialisationState} from 'mattermost-redux/actions/preferences';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled, UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled, UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
||||||
@@ -13,7 +12,6 @@ import {
|
|||||||
get,
|
get,
|
||||||
getBool,
|
getBool,
|
||||||
isCollapsedThreadsEnabled,
|
isCollapsedThreadsEnabled,
|
||||||
onboardingTourTipsEnabled,
|
|
||||||
} from 'mattermost-redux/selectors/entities/preferences';
|
} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentTeam, getCurrentTeamId, getTeam, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeam, getCurrentTeamId, getTeam, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
|
||||||
@@ -129,8 +127,7 @@ function makeMapStateToProps() {
|
|||||||
const user = getUser(state, post.user_id);
|
const user = getUser(state, post.user_id);
|
||||||
const isBot = Boolean(user && user.is_bot);
|
const isBot = Boolean(user && user.is_bot);
|
||||||
const highlightedPostId = getHighlightedPostId(state);
|
const highlightedPostId = getHighlightedPostId(state);
|
||||||
const showActionsMenuPulsatingDot = showActionsDropdownPulsatingDot(state);
|
|
||||||
const tourTipsEnabled = onboardingTourTipsEnabled(state);
|
|
||||||
const selectedCard = getSelectedPostCard(state);
|
const selectedCard = getSelectedPostCard(state);
|
||||||
|
|
||||||
let emojis: Emoji[] = [];
|
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,
|
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',
|
colorizeUsernames: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLORIZE_USERNAMES, Preferences.COLORIZE_USERNAMES_DEFAULT) === 'true',
|
||||||
shouldShowActionsMenu: shouldShowActionsMenu(state, post),
|
shouldShowActionsMenu: shouldShowActionsMenu(state, post),
|
||||||
showActionsMenuPulsatingDot,
|
|
||||||
tourTipsEnabled,
|
|
||||||
shortcutReactToLastPostEmittedFrom,
|
shortcutReactToLastPostEmittedFrom,
|
||||||
isBot,
|
isBot,
|
||||||
collapsedThreadsEnabled: isCollapsedThreadsEnabled(state),
|
collapsedThreadsEnabled: isCollapsedThreadsEnabled(state),
|
||||||
|
|||||||
@@ -114,8 +114,6 @@ export type Props = {
|
|||||||
isPostAcknowledgementsEnabled: boolean;
|
isPostAcknowledgementsEnabled: boolean;
|
||||||
isPostPriorityEnabled: boolean;
|
isPostPriorityEnabled: boolean;
|
||||||
isCardOpen?: boolean;
|
isCardOpen?: boolean;
|
||||||
shouldShowDotMenu: boolean;
|
|
||||||
tourTipsEnabled: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const PostComponent = (props: Props): JSX.Element => {
|
const PostComponent = (props: Props): JSX.Element => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import React, {ReactNode, useEffect, useRef, useState} from 'react';
|
|||||||
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
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 {isPostEphemeral} from 'mattermost-redux/utils/post_utils';
|
||||||
|
|
||||||
import {Locations} from 'utils/constants';
|
import {Locations} from 'utils/constants';
|
||||||
@@ -34,8 +34,6 @@ type Props = {
|
|||||||
handleDropdownOpened?: (e: boolean) => void;
|
handleDropdownOpened?: (e: boolean) => void;
|
||||||
collapsedThreadsEnabled?: boolean;
|
collapsedThreadsEnabled?: boolean;
|
||||||
shouldShowActionsMenu?: boolean;
|
shouldShowActionsMenu?: boolean;
|
||||||
showActionsMenuPulsatingDot?: boolean;
|
|
||||||
tourTipsEnabled: boolean;
|
|
||||||
oneClickReactionsEnabled?: boolean;
|
oneClickReactionsEnabled?: boolean;
|
||||||
recentEmojis: Emoji[];
|
recentEmojis: Emoji[];
|
||||||
isExpanded?: boolean;
|
isExpanded?: boolean;
|
||||||
@@ -51,7 +49,6 @@ type Props = {
|
|||||||
shortcutReactToLastPostEmittedFrom?: string;
|
shortcutReactToLastPostEmittedFrom?: string;
|
||||||
isPostHeaderVisible?: boolean | null;
|
isPostHeaderVisible?: boolean | null;
|
||||||
isPostBeingEdited?: boolean;
|
isPostBeingEdited?: boolean;
|
||||||
shouldShowDotMenu: boolean;
|
|
||||||
actions: {
|
actions: {
|
||||||
emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void;
|
emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void;
|
||||||
};
|
};
|
||||||
@@ -63,7 +60,6 @@ const PostOptions = (props: Props): JSX.Element => {
|
|||||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||||
const [showDotMenu, setShowDotMenu] = useState(false);
|
const [showDotMenu, setShowDotMenu] = useState(false);
|
||||||
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
||||||
const [showActionTip, setShowActionTip] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.isLastPost &&
|
if (props.isLastPost &&
|
||||||
@@ -80,8 +76,6 @@ const PostOptions = (props: Props): JSX.Element => {
|
|||||||
isReadOnly,
|
isReadOnly,
|
||||||
post,
|
post,
|
||||||
oneClickReactionsEnabled,
|
oneClickReactionsEnabled,
|
||||||
showActionsMenuPulsatingDot,
|
|
||||||
tourTipsEnabled,
|
|
||||||
isMobileView,
|
isMobileView,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -102,34 +96,14 @@ const PostOptions = (props: Props): JSX.Element => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleActionsMenuOpened = (open: boolean) => {
|
const handleActionsMenuOpened = (open: boolean) => {
|
||||||
if (tourTipsEnabled && showActionsMenuPulsatingDot) {
|
|
||||||
setShowActionTip(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setShowActionsMenu(open);
|
setShowActionsMenu(open);
|
||||||
props.handleDropdownOpened!(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 getDotMenuRef = () => dotMenuRef.current;
|
||||||
|
|
||||||
const isPostDeleted = post && post.state === Posts.POST_DELETED;
|
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 ||
|
const showCommentIcon = isFromAutoResponder || (!systemMessage && (isMobileView ||
|
||||||
hoverLocal || (!post.root_id && Boolean(props.hasReplies)) ||
|
hoverLocal || (!post.root_id && Boolean(props.hasReplies)) ||
|
||||||
props.isFirstReply) && props.location === Locations.CENTER);
|
props.isFirstReply) && props.location === Locations.CENTER);
|
||||||
@@ -197,11 +171,6 @@ const PostOptions = (props: Props): JSX.Element => {
|
|||||||
location={props.location}
|
location={props.location}
|
||||||
handleDropdownOpened={handleActionsMenuOpened}
|
handleDropdownOpened={handleActionsMenuOpened}
|
||||||
isMenuOpen={showActionsMenu}
|
isMenuOpen={showActionsMenu}
|
||||||
showPulsatingDot={tourTipsEnabled && showActionsMenuPulsatingDot}
|
|
||||||
showTutorialTip={tourTipsEnabled && showActionTip}
|
|
||||||
handleOpenTip={handleActionsMenuTipOpened}
|
|
||||||
handleNextTip={handleActionsMenuGotItClick}
|
|
||||||
handleDismissTip={handleTipDismissed}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const dotMenu = (
|
const dotMenu = (
|
||||||
@@ -231,7 +200,7 @@ const PostOptions = (props: Props): JSX.Element => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (isPostDeleted || !props.shouldShowDotMenu) {
|
} else if (isPostDeleted) {
|
||||||
options = null;
|
options = null;
|
||||||
} else if (props.location === Locations.SEARCH) {
|
} else if (props.location === Locations.SEARCH) {
|
||||||
const hasCRTFooter = props.collapsedThreadsEnabled && !post.root_id && (post.reply_count > 0 || post.is_following);
|
const hasCRTFooter = props.collapsedThreadsEnabled && !post.root_id && (post.reply_count > 0 || post.is_following);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ type Props = {
|
|||||||
previousPostId: string;
|
previousPostId: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
timestampProps?: Partial<TimestampProps>;
|
timestampProps?: Partial<TimestampProps>;
|
||||||
lastPost: Post;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function noop() {}
|
function noop() {}
|
||||||
|
|||||||
@@ -403,7 +403,6 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
|||||||
previousPostId={getPreviousPostId(data, index)}
|
previousPostId={getPreviousPostId(data, index)}
|
||||||
teamId={this.props.teamId}
|
teamId={this.props.teamId}
|
||||||
timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined}
|
timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined}
|
||||||
lastPost={this.props.lastPost}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {makeGetCustomStatus, getRecentCustomStatuses, isCustomStatusEnabled, sho
|
|||||||
|
|
||||||
import {TestHelper} from 'utils/test_helper';
|
import {TestHelper} from 'utils/test_helper';
|
||||||
import {CustomStatusDuration} from '@mattermost/types/users';
|
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/users');
|
||||||
jest.mock('mattermost-redux/selectors/entities/general');
|
jest.mock('mattermost-redux/selectors/entities/general');
|
||||||
@@ -86,6 +87,7 @@ describe('isCustomStatusEnabled', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton', () => {
|
describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton', () => {
|
||||||
|
const user = TestHelper.getUserMock();
|
||||||
const preference = {
|
const preference = {
|
||||||
myPreference: {
|
myPreference: {
|
||||||
value: '',
|
value: '',
|
||||||
@@ -104,4 +106,31 @@ describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton',
|
|||||||
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
|
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
|
||||||
expect(showPostHeaderUpdateStatusButton(store.getState())).toBeFalsy();
|
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 {Preferences} from 'mattermost-redux/constants';
|
||||||
import {CustomStatusDuration, UserCustomStatus} from '@mattermost/types/users';
|
import {CustomStatusDuration, UserCustomStatus} from '@mattermost/types/users';
|
||||||
|
|
||||||
|
import {isDateWithinDaysRange, TimeInformation} from 'utils/utils';
|
||||||
|
|
||||||
import {GlobalState} from 'types/store';
|
import {GlobalState} from 'types/store';
|
||||||
import {getCurrentUserTimezone} from 'selectors/general';
|
import {getCurrentUserTimezone} from 'selectors/general';
|
||||||
import {getCurrentMomentForTimezone} from 'utils/timezone';
|
import {getCurrentMomentForTimezone} from 'utils/timezone';
|
||||||
@@ -56,9 +58,12 @@ export function isCustomStatusEnabled(state: GlobalState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showCustomStatusPulsatingDotAndPostHeader(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 customStatusTutorialState = get(state, Preferences.CATEGORY_CUSTOM_STATUS, Preferences.NAME_CUSTOM_STATUS_TUTORIAL_STATE);
|
||||||
const modalAlreadyViewed = customStatusTutorialState && JSON.parse(customStatusTutorialState)[Preferences.CUSTOM_STATUS_MODAL_VIEWED];
|
const modalAlreadyViewed = customStatusTutorialState && JSON.parse(customStatusTutorialState)[Preferences.CUSTOM_STATUS_MODAL_VIEWED];
|
||||||
return !modalAlreadyViewed;
|
return !modalAlreadyViewed && hasUserCreationMoreThanSevenDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showStatusDropdownPulsatingDot(state: GlobalState) {
|
export function showStatusDropdownPulsatingDot(state: GlobalState) {
|
||||||
|
|||||||
@@ -90,6 +90,23 @@ const CLICKABLE_ELEMENTS = [
|
|||||||
'audio',
|
'audio',
|
||||||
'video',
|
'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() {
|
export function isMac() {
|
||||||
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
@@ -256,7 +273,6 @@ export function getTimestamp(): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number {
|
export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number {
|
||||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
||||||
const futureDate = new Date(timestamp as number);
|
const futureDate = new Date(timestamp as number);
|
||||||
const utcFuture = Date.UTC(futureDate.getFullYear(), futureDate.getMonth(), futureDate.getDate());
|
const utcFuture = Date.UTC(futureDate.getFullYear(), futureDate.getMonth(), futureDate.getDate());
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@@ -265,6 +281,39 @@ export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number
|
|||||||
return Math.floor((utcFuture - utcToday) / MS_PER_DAY);
|
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 = '') {
|
export function getLocaleDateFromUTC(timestamp: number, format = 'YYYY/MM/DD HH:mm:ss', userTimezone = '') {
|
||||||
if (!timestamp) {
|
if (!timestamp) {
|
||||||
return moment.now();
|
return moment.now();
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user