[MM-62987] Include description on aria-label for last reply time, make link focused when using up/down arrows. (#30837)
* [MM-62987] Include description on aria-label for last reply time, make link focused when using up/down arrows. * PR feedback --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c33dbe8d37
Коммит
0058edb806
@@ -1,371 +1,449 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`components/threading/global_threads/thread_item should report total number of replies 1`] = `
|
exports[`components/threading/global_threads/thread_item should report total number of replies 1`] = `
|
||||||
<div
|
<Fragment>
|
||||||
aria-label="Thread by Someone"
|
|
||||||
className="ThreadItem"
|
|
||||||
id=""
|
|
||||||
onClick={[Function]}
|
|
||||||
onKeyDown={[Function]}
|
|
||||||
role="link"
|
|
||||||
tabIndex={0}
|
|
||||||
>
|
|
||||||
<header>
|
|
||||||
<div
|
|
||||||
className="ThreadItem__author"
|
|
||||||
>
|
|
||||||
Someone
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="ThreadItem__tags"
|
|
||||||
>
|
|
||||||
<Memo(Tag)
|
|
||||||
onClick={[Function]}
|
|
||||||
text="Team name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<MockTimestamp
|
|
||||||
className="alt-hidden"
|
|
||||||
day="numeric"
|
|
||||||
units={
|
|
||||||
Array [
|
|
||||||
"now",
|
|
||||||
"minute",
|
|
||||||
"hour",
|
|
||||||
"day",
|
|
||||||
"week",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
useTime={false}
|
|
||||||
/>
|
|
||||||
</header>
|
|
||||||
<div
|
<div
|
||||||
className="menu-anchor alt-visible"
|
aria-describedby="ThreadItem__timestamp_1y8hpek81byspd4enyk9mp1ncw"
|
||||||
>
|
aria-label="Thread by Someone"
|
||||||
<MockThreadMenu
|
className="ThreadItem"
|
||||||
hasUnreads={false}
|
id=""
|
||||||
isFollowing={true}
|
|
||||||
threadId="1y8hpek81byspd4enyk9mp1ncw"
|
|
||||||
unreadTimestamp={1611786714912}
|
|
||||||
>
|
|
||||||
<WithTooltip
|
|
||||||
title={
|
|
||||||
<Memo(MemoizedFormattedMessage)
|
|
||||||
defaultMessage="Actions"
|
|
||||||
id="threading.threadItem.menu"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Memo(Button)
|
|
||||||
aria-label="Actions"
|
|
||||||
className="Button___icon"
|
|
||||||
marginTop={true}
|
|
||||||
>
|
|
||||||
<DotsVerticalIcon
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</Memo(Button)>
|
|
||||||
</WithTooltip>
|
|
||||||
</MockThreadMenu>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="preview"
|
|
||||||
dir="auto"
|
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<MockMarkdown
|
<header>
|
||||||
imageProps={
|
<div
|
||||||
Object {
|
className="ThreadItem__author"
|
||||||
"onImageHeightChanged": [Function],
|
>
|
||||||
"onImageLoaded": [Function],
|
Someone
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="ThreadItem__tags"
|
||||||
|
>
|
||||||
|
<Memo(Tag)
|
||||||
|
onClick={[Function]}
|
||||||
|
text="Team name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<MockTimestamp
|
||||||
|
className="alt-hidden"
|
||||||
|
day="numeric"
|
||||||
|
units={
|
||||||
|
Array [
|
||||||
|
"now",
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
useTime={false}
|
||||||
mentionKeys={Array []}
|
/>
|
||||||
message="test msg"
|
</header>
|
||||||
options={
|
<div
|
||||||
Object {
|
className="menu-anchor alt-visible"
|
||||||
"atMentions": true,
|
>
|
||||||
"mentionHighlight": false,
|
<MockThreadMenu
|
||||||
"singleline": true,
|
hasUnreads={false}
|
||||||
|
isFollowing={true}
|
||||||
|
threadId="1y8hpek81byspd4enyk9mp1ncw"
|
||||||
|
unreadTimestamp={1611786714912}
|
||||||
|
>
|
||||||
|
<WithTooltip
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Actions"
|
||||||
|
id="threading.threadItem.menu"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Memo(Button)
|
||||||
|
aria-label="Actions"
|
||||||
|
className="Button___icon"
|
||||||
|
marginTop={true}
|
||||||
|
>
|
||||||
|
<DotsVerticalIcon
|
||||||
|
size={18}
|
||||||
|
/>
|
||||||
|
</Memo(Button)>
|
||||||
|
</WithTooltip>
|
||||||
|
</MockThreadMenu>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="preview"
|
||||||
|
dir="auto"
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
>
|
||||||
|
<MockMarkdown
|
||||||
|
imageProps={
|
||||||
|
Object {
|
||||||
|
"onImageHeightChanged": [Function],
|
||||||
|
"onImageLoaded": [Function],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
mentionKeys={Array []}
|
||||||
/>
|
message="test msg"
|
||||||
|
options={
|
||||||
|
Object {
|
||||||
|
"atMentions": true,
|
||||||
|
"mentionHighlight": false,
|
||||||
|
"singleline": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="activity"
|
||||||
|
>
|
||||||
|
<MockAvatars
|
||||||
|
size="xs"
|
||||||
|
userIds={
|
||||||
|
Array [
|
||||||
|
"mt5td9mdriyapmwuh5pc84dmhr",
|
||||||
|
"ij61jet1bbdk8fhhxitywdj4ih",
|
||||||
|
"7n4ach3i53bbmj84dfmu5b7c1c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="{totalReplies, plural, =0 {Reply} =1 {# reply} other {# replies}}"
|
||||||
|
id="threading.numReplies"
|
||||||
|
values={
|
||||||
|
Object {
|
||||||
|
"totalReplies": 9,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className="sr-only"
|
||||||
|
id="ThreadItem__timestamp_1y8hpek81byspd4enyk9mp1ncw"
|
||||||
|
>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="Last reply "
|
||||||
|
id="threading.threadItem.timestamp"
|
||||||
|
/>
|
||||||
|
<MockTimestamp
|
||||||
|
className="alt-hidden"
|
||||||
|
day="numeric"
|
||||||
|
units={
|
||||||
|
Array [
|
||||||
|
"now",
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
useTime={false}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
</Fragment>
|
||||||
className="activity"
|
|
||||||
>
|
|
||||||
<MockAvatars
|
|
||||||
size="xs"
|
|
||||||
userIds={
|
|
||||||
Array [
|
|
||||||
"mt5td9mdriyapmwuh5pc84dmhr",
|
|
||||||
"ij61jet1bbdk8fhhxitywdj4ih",
|
|
||||||
"7n4ach3i53bbmj84dfmu5b7c1c",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<MemoizedFormattedMessage
|
|
||||||
defaultMessage="{totalReplies, plural, =0 {Reply} =1 {# reply} other {# replies}}"
|
|
||||||
id="threading.numReplies"
|
|
||||||
values={
|
|
||||||
Object {
|
|
||||||
"totalReplies": 9,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/threading/global_threads/thread_item should report unread mentions 1`] = `
|
exports[`components/threading/global_threads/thread_item should report unread mentions 1`] = `
|
||||||
<div
|
<Fragment>
|
||||||
aria-label="Thread by Someone"
|
|
||||||
className="ThreadItem has-unreads"
|
|
||||||
id=""
|
|
||||||
onClick={[Function]}
|
|
||||||
onKeyDown={[Function]}
|
|
||||||
role="link"
|
|
||||||
tabIndex={0}
|
|
||||||
>
|
|
||||||
<header>
|
|
||||||
<div
|
|
||||||
className="indicator"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="dot-mentions"
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="ThreadItem__author"
|
|
||||||
>
|
|
||||||
Someone
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="ThreadItem__tags"
|
|
||||||
>
|
|
||||||
<Memo(Tag)
|
|
||||||
onClick={[Function]}
|
|
||||||
text="Team name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<MockTimestamp
|
|
||||||
className="alt-hidden"
|
|
||||||
day="numeric"
|
|
||||||
units={
|
|
||||||
Array [
|
|
||||||
"now",
|
|
||||||
"minute",
|
|
||||||
"hour",
|
|
||||||
"day",
|
|
||||||
"week",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
useTime={false}
|
|
||||||
/>
|
|
||||||
</header>
|
|
||||||
<div
|
<div
|
||||||
className="menu-anchor alt-visible"
|
aria-describedby="ThreadItem__timestamp_1y8hpek81byspd4enyk9mp1ncw"
|
||||||
>
|
aria-label="Thread by Someone"
|
||||||
<MockThreadMenu
|
className="ThreadItem has-unreads"
|
||||||
hasUnreads={true}
|
id=""
|
||||||
isFollowing={true}
|
|
||||||
threadId="1y8hpek81byspd4enyk9mp1ncw"
|
|
||||||
unreadTimestamp={1611786714912}
|
|
||||||
>
|
|
||||||
<WithTooltip
|
|
||||||
title={
|
|
||||||
<Memo(MemoizedFormattedMessage)
|
|
||||||
defaultMessage="Actions"
|
|
||||||
id="threading.threadItem.menu"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Memo(Button)
|
|
||||||
aria-label="Actions"
|
|
||||||
className="Button___icon"
|
|
||||||
marginTop={true}
|
|
||||||
>
|
|
||||||
<DotsVerticalIcon
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</Memo(Button)>
|
|
||||||
</WithTooltip>
|
|
||||||
</MockThreadMenu>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="preview"
|
|
||||||
dir="auto"
|
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<MockMarkdown
|
<header>
|
||||||
imageProps={
|
<div
|
||||||
Object {
|
className="indicator"
|
||||||
"onImageHeightChanged": [Function],
|
>
|
||||||
"onImageLoaded": [Function],
|
<div
|
||||||
|
className="dot-mentions"
|
||||||
|
>
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="ThreadItem__author"
|
||||||
|
>
|
||||||
|
Someone
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="ThreadItem__tags"
|
||||||
|
>
|
||||||
|
<Memo(Tag)
|
||||||
|
onClick={[Function]}
|
||||||
|
text="Team name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<MockTimestamp
|
||||||
|
className="alt-hidden"
|
||||||
|
day="numeric"
|
||||||
|
units={
|
||||||
|
Array [
|
||||||
|
"now",
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
useTime={false}
|
||||||
mentionKeys={Array []}
|
/>
|
||||||
message="test msg"
|
</header>
|
||||||
options={
|
<div
|
||||||
Object {
|
className="menu-anchor alt-visible"
|
||||||
"atMentions": true,
|
>
|
||||||
"mentionHighlight": false,
|
<MockThreadMenu
|
||||||
"singleline": true,
|
hasUnreads={true}
|
||||||
|
isFollowing={true}
|
||||||
|
threadId="1y8hpek81byspd4enyk9mp1ncw"
|
||||||
|
unreadTimestamp={1611786714912}
|
||||||
|
>
|
||||||
|
<WithTooltip
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Actions"
|
||||||
|
id="threading.threadItem.menu"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Memo(Button)
|
||||||
|
aria-label="Actions"
|
||||||
|
className="Button___icon"
|
||||||
|
marginTop={true}
|
||||||
|
>
|
||||||
|
<DotsVerticalIcon
|
||||||
|
size={18}
|
||||||
|
/>
|
||||||
|
</Memo(Button)>
|
||||||
|
</WithTooltip>
|
||||||
|
</MockThreadMenu>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="preview"
|
||||||
|
dir="auto"
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
>
|
||||||
|
<MockMarkdown
|
||||||
|
imageProps={
|
||||||
|
Object {
|
||||||
|
"onImageHeightChanged": [Function],
|
||||||
|
"onImageLoaded": [Function],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
mentionKeys={Array []}
|
||||||
/>
|
message="test msg"
|
||||||
|
options={
|
||||||
|
Object {
|
||||||
|
"atMentions": true,
|
||||||
|
"mentionHighlight": false,
|
||||||
|
"singleline": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="activity"
|
||||||
|
>
|
||||||
|
<MockAvatars
|
||||||
|
size="xs"
|
||||||
|
userIds={
|
||||||
|
Array [
|
||||||
|
"mt5td9mdriyapmwuh5pc84dmhr",
|
||||||
|
"ij61jet1bbdk8fhhxitywdj4ih",
|
||||||
|
"7n4ach3i53bbmj84dfmu5b7c1c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="{newReplies, plural, =1 {# new reply} other {# new replies}}"
|
||||||
|
id="threading.numNewReplies"
|
||||||
|
values={
|
||||||
|
Object {
|
||||||
|
"newReplies": 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className="sr-only"
|
||||||
|
id="ThreadItem__timestamp_1y8hpek81byspd4enyk9mp1ncw"
|
||||||
|
>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="Last reply "
|
||||||
|
id="threading.threadItem.timestamp"
|
||||||
|
/>
|
||||||
|
<MockTimestamp
|
||||||
|
className="alt-hidden"
|
||||||
|
day="numeric"
|
||||||
|
units={
|
||||||
|
Array [
|
||||||
|
"now",
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
useTime={false}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
</Fragment>
|
||||||
className="activity"
|
|
||||||
>
|
|
||||||
<MockAvatars
|
|
||||||
size="xs"
|
|
||||||
userIds={
|
|
||||||
Array [
|
|
||||||
"mt5td9mdriyapmwuh5pc84dmhr",
|
|
||||||
"ij61jet1bbdk8fhhxitywdj4ih",
|
|
||||||
"7n4ach3i53bbmj84dfmu5b7c1c",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<MemoizedFormattedMessage
|
|
||||||
defaultMessage="{newReplies, plural, =1 {# new reply} other {# new replies}}"
|
|
||||||
id="threading.numNewReplies"
|
|
||||||
values={
|
|
||||||
Object {
|
|
||||||
"newReplies": 5,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/threading/global_threads/thread_item should report unread messages 1`] = `
|
exports[`components/threading/global_threads/thread_item should report unread messages 1`] = `
|
||||||
<div
|
<Fragment>
|
||||||
aria-label="Thread by Someone"
|
|
||||||
className="ThreadItem has-unreads"
|
|
||||||
id=""
|
|
||||||
onClick={[Function]}
|
|
||||||
onKeyDown={[Function]}
|
|
||||||
role="link"
|
|
||||||
tabIndex={0}
|
|
||||||
>
|
|
||||||
<header>
|
|
||||||
<div
|
|
||||||
className="indicator"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="dot-unreads"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="ThreadItem__author"
|
|
||||||
>
|
|
||||||
Someone
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="ThreadItem__tags"
|
|
||||||
>
|
|
||||||
<Memo(Tag)
|
|
||||||
onClick={[Function]}
|
|
||||||
text="Team name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<MockTimestamp
|
|
||||||
className="alt-hidden"
|
|
||||||
day="numeric"
|
|
||||||
units={
|
|
||||||
Array [
|
|
||||||
"now",
|
|
||||||
"minute",
|
|
||||||
"hour",
|
|
||||||
"day",
|
|
||||||
"week",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
useTime={false}
|
|
||||||
/>
|
|
||||||
</header>
|
|
||||||
<div
|
<div
|
||||||
className="menu-anchor alt-visible"
|
aria-describedby="ThreadItem__timestamp_1y8hpek81byspd4enyk9mp1ncw"
|
||||||
>
|
aria-label="Thread by Someone"
|
||||||
<MockThreadMenu
|
className="ThreadItem has-unreads"
|
||||||
hasUnreads={true}
|
id=""
|
||||||
isFollowing={true}
|
|
||||||
threadId="1y8hpek81byspd4enyk9mp1ncw"
|
|
||||||
unreadTimestamp={1611786714912}
|
|
||||||
>
|
|
||||||
<WithTooltip
|
|
||||||
title={
|
|
||||||
<Memo(MemoizedFormattedMessage)
|
|
||||||
defaultMessage="Actions"
|
|
||||||
id="threading.threadItem.menu"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Memo(Button)
|
|
||||||
aria-label="Actions"
|
|
||||||
className="Button___icon"
|
|
||||||
marginTop={true}
|
|
||||||
>
|
|
||||||
<DotsVerticalIcon
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</Memo(Button)>
|
|
||||||
</WithTooltip>
|
|
||||||
</MockThreadMenu>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="preview"
|
|
||||||
dir="auto"
|
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<MockMarkdown
|
<header>
|
||||||
imageProps={
|
<div
|
||||||
Object {
|
className="indicator"
|
||||||
"onImageHeightChanged": [Function],
|
>
|
||||||
"onImageLoaded": [Function],
|
<div
|
||||||
|
className="dot-unreads"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="ThreadItem__author"
|
||||||
|
>
|
||||||
|
Someone
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="ThreadItem__tags"
|
||||||
|
>
|
||||||
|
<Memo(Tag)
|
||||||
|
onClick={[Function]}
|
||||||
|
text="Team name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<MockTimestamp
|
||||||
|
className="alt-hidden"
|
||||||
|
day="numeric"
|
||||||
|
units={
|
||||||
|
Array [
|
||||||
|
"now",
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
useTime={false}
|
||||||
mentionKeys={Array []}
|
/>
|
||||||
message="test msg"
|
</header>
|
||||||
options={
|
<div
|
||||||
Object {
|
className="menu-anchor alt-visible"
|
||||||
"atMentions": true,
|
>
|
||||||
"mentionHighlight": false,
|
<MockThreadMenu
|
||||||
"singleline": true,
|
hasUnreads={true}
|
||||||
|
isFollowing={true}
|
||||||
|
threadId="1y8hpek81byspd4enyk9mp1ncw"
|
||||||
|
unreadTimestamp={1611786714912}
|
||||||
|
>
|
||||||
|
<WithTooltip
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Actions"
|
||||||
|
id="threading.threadItem.menu"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Memo(Button)
|
||||||
|
aria-label="Actions"
|
||||||
|
className="Button___icon"
|
||||||
|
marginTop={true}
|
||||||
|
>
|
||||||
|
<DotsVerticalIcon
|
||||||
|
size={18}
|
||||||
|
/>
|
||||||
|
</Memo(Button)>
|
||||||
|
</WithTooltip>
|
||||||
|
</MockThreadMenu>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="preview"
|
||||||
|
dir="auto"
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
>
|
||||||
|
<MockMarkdown
|
||||||
|
imageProps={
|
||||||
|
Object {
|
||||||
|
"onImageHeightChanged": [Function],
|
||||||
|
"onImageLoaded": [Function],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
mentionKeys={Array []}
|
||||||
/>
|
message="test msg"
|
||||||
|
options={
|
||||||
|
Object {
|
||||||
|
"atMentions": true,
|
||||||
|
"mentionHighlight": false,
|
||||||
|
"singleline": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="activity"
|
||||||
|
>
|
||||||
|
<MockAvatars
|
||||||
|
size="xs"
|
||||||
|
userIds={
|
||||||
|
Array [
|
||||||
|
"mt5td9mdriyapmwuh5pc84dmhr",
|
||||||
|
"ij61jet1bbdk8fhhxitywdj4ih",
|
||||||
|
"7n4ach3i53bbmj84dfmu5b7c1c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="{newReplies, plural, =1 {# new reply} other {# new replies}}"
|
||||||
|
id="threading.numNewReplies"
|
||||||
|
values={
|
||||||
|
Object {
|
||||||
|
"newReplies": 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className="sr-only"
|
||||||
|
id="ThreadItem__timestamp_1y8hpek81byspd4enyk9mp1ncw"
|
||||||
|
>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="Last reply "
|
||||||
|
id="threading.threadItem.timestamp"
|
||||||
|
/>
|
||||||
|
<MockTimestamp
|
||||||
|
className="alt-hidden"
|
||||||
|
day="numeric"
|
||||||
|
units={
|
||||||
|
Array [
|
||||||
|
"now",
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
useTime={false}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
</Fragment>
|
||||||
className="activity"
|
|
||||||
>
|
|
||||||
<MockAvatars
|
|
||||||
size="xs"
|
|
||||||
userIds={
|
|
||||||
Array [
|
|
||||||
"mt5td9mdriyapmwuh5pc84dmhr",
|
|
||||||
"ij61jet1bbdk8fhhxitywdj4ih",
|
|
||||||
"7n4ach3i53bbmj84dfmu5b7c1c",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<MemoizedFormattedMessage
|
|
||||||
defaultMessage="{newReplies, plural, =1 {# new reply} other {# new replies}}"
|
|
||||||
id="threading.numNewReplies"
|
|
||||||
values={
|
|
||||||
Object {
|
|
||||||
"newReplies": 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ describe('components/threading/global_threads/thread_item', () => {
|
|||||||
|
|
||||||
test('should allow marking as unread on alt + click', () => {
|
test('should allow marking as unread on alt + click', () => {
|
||||||
const wrapper = shallow(<ThreadItem {...props}/>);
|
const wrapper = shallow(<ThreadItem {...props}/>);
|
||||||
wrapper.simulate('click', {altKey: true});
|
wrapper.find('div.ThreadItem').simulate('click', {altKey: true});
|
||||||
expect(updateThreadRead).not.toHaveBeenCalled();
|
expect(updateThreadRead).not.toHaveBeenCalled();
|
||||||
expect(markLastPostInThreadAsUnread).toHaveBeenCalledWith('user_id', 'tid', '1y8hpek81byspd4enyk9mp1ncw');
|
expect(markLastPostInThreadAsUnread).toHaveBeenCalledWith('user_id', 'tid', '1y8hpek81byspd4enyk9mp1ncw');
|
||||||
expect(manuallyMarkThreadAsUnread).toHaveBeenCalledWith('1y8hpek81byspd4enyk9mp1ncw', 1611786714912);
|
expect(manuallyMarkThreadAsUnread).toHaveBeenCalledWith('1y8hpek81byspd4enyk9mp1ncw', 1611786714912);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, {memo, useCallback, useEffect, useMemo} from 'react';
|
import React, {memo, useCallback, useEffect, useMemo, useRef} from 'react';
|
||||||
import type {MouseEvent, KeyboardEvent} from 'react';
|
import type {MouseEvent, KeyboardEvent} from 'react';
|
||||||
import {FormattedMessage, useIntl} from 'react-intl';
|
import {FormattedMessage, useIntl} from 'react-intl';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
@@ -94,6 +94,7 @@ function ThreadItem({
|
|||||||
const postAuthor = ensureString(post.props?.override_username) || displayName;
|
const postAuthor = ensureString(post.props?.override_username) || displayName;
|
||||||
const getMentionKeysForPost = useMemo(() => makeGetMentionKeysForPost(), []);
|
const getMentionKeysForPost = useMemo(() => makeGetMentionKeysForPost(), []);
|
||||||
const mentionsKeys = useSelector((state: GlobalState) => getMentionKeysForPost(state, post, channel));
|
const mentionsKeys = useSelector((state: GlobalState) => getMentionKeysForPost(state, post, channel));
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (channel?.teammate_id) {
|
if (channel?.teammate_id) {
|
||||||
@@ -107,6 +108,12 @@ function ThreadItem({
|
|||||||
}
|
}
|
||||||
}, [channel, thread?.post.channel_id]);
|
}, [channel, thread?.post.channel_id]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSelected) {
|
||||||
|
ref.current?.focus();
|
||||||
|
}
|
||||||
|
}, [isSelected, threadId]);
|
||||||
|
|
||||||
const participantIds = useMemo(() => {
|
const participantIds = useMemo(() => {
|
||||||
const ids = (thread?.participants || []).flatMap(({id}) => {
|
const ids = (thread?.participants || []).flatMap(({id}) => {
|
||||||
if (id === post.user_id) {
|
if (id === post.user_id) {
|
||||||
@@ -188,134 +195,152 @@ function ThreadItem({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
style={style}
|
<div
|
||||||
className={classNames('ThreadItem', {
|
style={style}
|
||||||
'has-unreads': newReplies,
|
className={classNames('ThreadItem', {
|
||||||
'is-selected': isSelected,
|
'has-unreads': newReplies,
|
||||||
})}
|
'is-selected': isSelected,
|
||||||
tabIndex={isSelected ? -1 : 0}
|
})}
|
||||||
role='link'
|
tabIndex={isSelected ? -1 : 0}
|
||||||
aria-label={formatMessage(
|
role='link'
|
||||||
{id: 'threading.threadItem.ariaLabel', defaultMessage: 'Thread by {author}'},
|
aria-label={formatMessage(
|
||||||
{author: postAuthor},
|
{id: 'threading.threadItem.ariaLabel', defaultMessage: 'Thread by {author}'},
|
||||||
)}
|
{author: postAuthor},
|
||||||
id={isFirstThreadInList ? 'tutorial-threads-mobile-list' : ''}
|
)}
|
||||||
onClick={selectHandler}
|
aria-describedby={`ThreadItem__timestamp_${threadId}`}
|
||||||
onKeyDown={selectHandler}
|
id={isFirstThreadInList ? 'tutorial-threads-mobile-list' : ''}
|
||||||
>
|
onClick={selectHandler}
|
||||||
<header>
|
onKeyDown={selectHandler}
|
||||||
{Boolean(newMentions || newReplies) && (
|
ref={ref}
|
||||||
<div className='indicator'>
|
>
|
||||||
{newMentions ? (
|
<header>
|
||||||
<div className={classNames('dot-mentions', {over: newMentions > 99})}>
|
{Boolean(newMentions || newReplies) && (
|
||||||
{Math.min(newMentions, 99)}
|
<div className='indicator'>
|
||||||
{newMentions > 99 && '+'}
|
{newMentions ? (
|
||||||
</div>
|
<div className={classNames('dot-mentions', {over: newMentions > 99})}>
|
||||||
) : (
|
{Math.min(newMentions, 99)}
|
||||||
<div className='dot-unreads'/>
|
{newMentions > 99 && '+'}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className='dot-unreads'/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className='ThreadItem__author'>{postAuthor}</div>
|
||||||
|
<div className='ThreadItem__tags'>
|
||||||
|
{channel && postAuthor !== channel?.display_name && (
|
||||||
|
<Tag
|
||||||
|
onClick={goToInChannelHandler}
|
||||||
|
text={channel?.display_name}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isPostPriorityEnabled && (
|
||||||
|
thread.is_urgent && (
|
||||||
|
<PriorityBadge
|
||||||
|
className={postAuthor === channel?.display_name ? 'ml-2' : ''}
|
||||||
|
priority={PostPriority.URGENT}
|
||||||
|
/>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
<Timestamp
|
||||||
<div className='ThreadItem__author'>{postAuthor}</div>
|
{...THREADING_TIME}
|
||||||
<div className='ThreadItem__tags'>
|
className='alt-hidden'
|
||||||
{channel && postAuthor !== channel?.display_name && (
|
value={lastReplyAt}
|
||||||
<Tag
|
/>
|
||||||
onClick={goToInChannelHandler}
|
</header>
|
||||||
text={channel?.display_name}
|
<div className='menu-anchor alt-visible'>
|
||||||
|
<ThreadMenu
|
||||||
|
threadId={threadId}
|
||||||
|
isFollowing={isFollowing ?? false}
|
||||||
|
hasUnreads={Boolean(newReplies)}
|
||||||
|
unreadTimestamp={unreadTimestamp}
|
||||||
|
>
|
||||||
|
<WithTooltip
|
||||||
|
title={(
|
||||||
|
<FormattedMessage
|
||||||
|
id='threading.threadItem.menu'
|
||||||
|
defaultMessage='Actions'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
marginTop={true}
|
||||||
|
className='Button___icon'
|
||||||
|
aria-label={formatMessage({
|
||||||
|
id: 'threading.threadItem.menu',
|
||||||
|
defaultMessage: 'Actions',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<DotsVerticalIcon size={18}/>
|
||||||
|
</Button>
|
||||||
|
</WithTooltip>
|
||||||
|
</ThreadMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* The strange interaction here where we need a click/keydown handler messes with the ESLint rules, so we just disable it */}
|
||||||
|
{/*eslint-disable-next-line jsx-a11y/no-static-element-interactions*/}
|
||||||
|
<div
|
||||||
|
className='preview'
|
||||||
|
dir='auto'
|
||||||
|
onClick={handleFormattedTextClick}
|
||||||
|
onKeyDown={handleFormattedTextClick}
|
||||||
|
>
|
||||||
|
{post.message ? (
|
||||||
|
<Markdown
|
||||||
|
message={post.state === Posts.POST_DELETED ? msgDeleted : post.message}
|
||||||
|
options={markdownPreviewOptions}
|
||||||
|
imagesMetadata={post?.metadata && post?.metadata?.images}
|
||||||
|
mentionKeys={mentionsKeys}
|
||||||
|
imageProps={imageProps}
|
||||||
/>
|
/>
|
||||||
)}
|
) : (
|
||||||
{isPostPriorityEnabled && (
|
<Attachment post={post}/>
|
||||||
thread.is_urgent && (
|
|
||||||
<PriorityBadge
|
|
||||||
className={postAuthor === channel?.display_name ? 'ml-2' : ''}
|
|
||||||
priority={PostPriority.URGENT}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Timestamp
|
<div className='activity'>
|
||||||
{...THREADING_TIME}
|
{participantIds?.length ? (
|
||||||
className='alt-hidden'
|
<Avatars
|
||||||
value={lastReplyAt}
|
userIds={participantIds}
|
||||||
/>
|
size='xs'
|
||||||
</header>
|
/>
|
||||||
<div className='menu-anchor alt-visible'>
|
) : null}
|
||||||
<ThreadMenu
|
{Boolean(totalReplies) && (
|
||||||
threadId={threadId}
|
<>
|
||||||
isFollowing={isFollowing ?? false}
|
{newReplies ? (
|
||||||
hasUnreads={Boolean(newReplies)}
|
<FormattedMessage
|
||||||
unreadTimestamp={unreadTimestamp}
|
id='threading.numNewReplies'
|
||||||
|
defaultMessage='{newReplies, plural, =1 {# new reply} other {# new replies}}'
|
||||||
|
values={{newReplies}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id='threading.numReplies'
|
||||||
|
defaultMessage='{totalReplies, plural, =0 {Reply} =1 {# reply} other {# replies}}'
|
||||||
|
values={{totalReplies}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{showListTutorialTip && isFirstThreadInList && isMobileView && (<CRTListTutorialTip/>)}
|
||||||
|
<span
|
||||||
|
className='sr-only'
|
||||||
|
id={`ThreadItem__timestamp_${threadId}`}
|
||||||
>
|
>
|
||||||
<WithTooltip
|
<FormattedMessage
|
||||||
title={(
|
id='threading.threadItem.timestamp'
|
||||||
<FormattedMessage
|
defaultMessage='Last reply '
|
||||||
id='threading.threadItem.menu'
|
|
||||||
defaultMessage='Actions'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
marginTop={true}
|
|
||||||
className='Button___icon'
|
|
||||||
aria-label={formatMessage({
|
|
||||||
id: 'threading.threadItem.menu',
|
|
||||||
defaultMessage: 'Actions',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<DotsVerticalIcon size={18}/>
|
|
||||||
</Button>
|
|
||||||
</WithTooltip>
|
|
||||||
</ThreadMenu>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* The strange interaction here where we need a click/keydown handler messes with the ESLint rules, so we just disable it */}
|
|
||||||
{/*eslint-disable-next-line jsx-a11y/no-static-element-interactions*/}
|
|
||||||
<div
|
|
||||||
className='preview'
|
|
||||||
dir='auto'
|
|
||||||
onClick={handleFormattedTextClick}
|
|
||||||
onKeyDown={handleFormattedTextClick}
|
|
||||||
>
|
|
||||||
{post.message ? (
|
|
||||||
<Markdown
|
|
||||||
message={post.state === Posts.POST_DELETED ? msgDeleted : post.message}
|
|
||||||
options={markdownPreviewOptions}
|
|
||||||
imagesMetadata={post?.metadata && post?.metadata?.images}
|
|
||||||
mentionKeys={mentionsKeys}
|
|
||||||
imageProps={imageProps}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
<Timestamp
|
||||||
<Attachment post={post}/>
|
{...THREADING_TIME}
|
||||||
)}
|
className='alt-hidden'
|
||||||
</div>
|
value={lastReplyAt}
|
||||||
<div className='activity'>
|
|
||||||
{participantIds?.length ? (
|
|
||||||
<Avatars
|
|
||||||
userIds={participantIds}
|
|
||||||
size='xs'
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
</span>
|
||||||
{Boolean(totalReplies) && (
|
|
||||||
<>
|
|
||||||
{newReplies ? (
|
|
||||||
<FormattedMessage
|
|
||||||
id='threading.numNewReplies'
|
|
||||||
defaultMessage='{newReplies, plural, =1 {# new reply} other {# new replies}}'
|
|
||||||
values={{newReplies}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<FormattedMessage
|
|
||||||
id='threading.numReplies'
|
|
||||||
defaultMessage='{totalReplies, plural, =0 {Reply} =1 {# reply} other {# replies}}'
|
|
||||||
values={{totalReplies}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{showListTutorialTip && isFirstThreadInList && isMobileView && (<CRTListTutorialTip/>)}
|
</>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,9 +120,7 @@ const ThreadList = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
select(data[threadIdToSelect]);
|
select(data[threadIdToSelect]);
|
||||||
|
e.preventDefault();
|
||||||
// hacky way to ensure the thread item loses focus.
|
|
||||||
ref.current?.focus();
|
|
||||||
}, [selectedThreadId, data]);
|
}, [selectedThreadId, data]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -5497,6 +5497,7 @@
|
|||||||
"threading.threadHeader.menu": "More Actions",
|
"threading.threadHeader.menu": "More Actions",
|
||||||
"threading.threadItem.ariaLabel": "Thread by {author}",
|
"threading.threadItem.ariaLabel": "Thread by {author}",
|
||||||
"threading.threadItem.menu": "Actions",
|
"threading.threadItem.menu": "Actions",
|
||||||
|
"threading.threadItem.timestamp": "Last reply ",
|
||||||
"threading.threadList.markRead": "Mark all threads as read",
|
"threading.threadList.markRead": "Mark all threads as read",
|
||||||
"threading.threadList.tabsLabel": "Filter visible threads",
|
"threading.threadList.tabsLabel": "Filter visible threads",
|
||||||
"threading.threadMenu.copy": "Copy link",
|
"threading.threadMenu.copy": "Copy link",
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user