From 514efd6cb16fa06c58ebfbb0dfd67b8e2d6cec93 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 26 Mar 2024 16:37:31 +0000 Subject: [PATCH 01/15] Mark all threads as read button --- res/css/views/right_panel/_ThreadPanel.pcss | 13 ++++++++- res/img/element-icons/check-all.svg | 6 +++++ src/components/structures/ThreadPanel.tsx | 30 +++++++++++++++++++++ src/i18n/strings/en_EN.json | 1 + 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 res/img/element-icons/check-all.svg diff --git a/res/css/views/right_panel/_ThreadPanel.pcss b/res/css/views/right_panel/_ThreadPanel.pcss index 9d14c993dfd..407d46a8db3 100644 --- a/res/css/views/right_panel/_ThreadPanel.pcss +++ b/res/css/views/right_panel/_ThreadPanel.pcss @@ -1,5 +1,5 @@ /* -Copyright 2021 The Matrix.org Foundation C.I.C. +Copyright 2021,2024 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,11 +20,22 @@ limitations under the License. .mx_BaseCard_header { .mx_BaseCard_header_title { + .mx_BaseCard_header_title_heading { + margin-right: auto; + } + .mx_AccessibleButton { font-size: 12px; color: $secondary-content; } + .mx_ThreadPanel_vertical_separator { + height: 16px; + margin-left: 12px; + margin-right: 4px; + border-left: 1px solid var(--cpd-color-gray-400); + } + .mx_ThreadPanel_dropdown { padding: 3px $spacing-4 3px $spacing-8; border-radius: 4px; diff --git a/res/img/element-icons/check-all.svg b/res/img/element-icons/check-all.svg new file mode 100644 index 00000000000..d81382504d3 --- /dev/null +++ b/res/img/element-icons/check-all.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index d43b4e25d16..6705fb4c8fa 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -17,7 +17,10 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; import React, { useContext, useEffect, useRef, useState } from "react"; import { EventTimelineSet, Room, Thread } from "matrix-js-sdk/src/matrix"; +import { IconButton, Tooltip } from "@vector-im/compound-web"; +import { logger } from "matrix-js-sdk/src/logger"; +import { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg"; import BaseCard from "../views/right_panel/BaseCard"; import ResizeNotifier from "../../utils/ResizeNotifier"; import MatrixClientContext from "../../contexts/MatrixClientContext"; @@ -33,6 +36,7 @@ import PosthogTrackers from "../../PosthogTrackers"; import { ButtonEvent } from "../views/elements/AccessibleButton"; import Spinner from "../views/elements/Spinner"; import Heading from "../views/typography/Heading"; +import { clearRoomNotification } from "../../utils/notifications"; interface IProps { roomId: string; @@ -71,6 +75,8 @@ export const ThreadPanelHeader: React.FC<{ setFilterOption: (filterOption: ThreadFilterType) => void; empty: boolean; }> = ({ filterOption, setFilterOption, empty }) => { + const mxClient = useContext(MatrixClientContext); + const roomContext = useContext(RoomContext); const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); const options: readonly ThreadPanelHeaderOption[] = [ { @@ -109,6 +115,20 @@ export const ThreadPanelHeader: React.FC<{ {contextMenuOptions} ) : null; + + const onMarkAllThreadsReadClick = React.useCallback(() => { + if (!roomContext.room) { + logger.error("No room in context to mark all threads read"); + return; + } + // This actually clears all room notifications by sending an unthreaded read receipt. + // We'd have to loop over all unread threads (pagninating back to find any we don't + // know about yet) and send threaded receipts for all of them... or implement a + // specific API for it. In practice, the user will have to be viewing the room to + // see this button, so will have marked the room itself read anyway. + clearRoomNotification(roomContext.room, mxClient); + }, [roomContext.room, mxClient]); + return (
@@ -116,6 +136,16 @@ export const ThreadPanelHeader: React.FC<{ {!empty && ( <> + + + + + +
Tip: Use ā€œ%(replyInThread)sā€ when hovering over a message.", "error_start_thread_existing_relation": "Can't create a thread from an event with an existing relation", + "mark_all_read": "Mark all as read", "my_threads": "My threads", "my_threads_description": "Shows all threads you've participated in", "open_thread": "Open thread", From 8151b752ed7d90ee8ffafe7dd82e61506c3ff421 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 26 Mar 2024 16:51:41 +0000 Subject: [PATCH 02/15] Wrap in TooltipProvider and update snapshots --- src/components/structures/ThreadPanel.tsx | 64 ++++++++++--------- .../__snapshots__/ThreadPanel-test.tsx.snap | 36 +++++++++++ 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 6705fb4c8fa..0f5df972537 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -17,7 +17,7 @@ limitations under the License. import { Optional } from "matrix-events-sdk"; import React, { useContext, useEffect, useRef, useState } from "react"; import { EventTimelineSet, Room, Thread } from "matrix-js-sdk/src/matrix"; -import { IconButton, Tooltip } from "@vector-im/compound-web"; +import { IconButton, Tooltip, TooltipProvider } from "@vector-im/compound-web"; import { logger } from "matrix-js-sdk/src/logger"; import { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg"; @@ -130,37 +130,39 @@ export const ThreadPanelHeader: React.FC<{ }, [roomContext.room, mxClient]); return ( -
- - {_t("common|threads")} - - {!empty && ( - <> - - +
+ + {_t("common|threads")} + + {!empty && ( + <> + + + + + +
+ { + openMenu(); + PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev); + }} > - - - -
- { - openMenu(); - PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev); - }} - > - {`${_t("threads|show_thread_filter")} ${value?.label}`} - - {contextMenu} - - )} -
+ {`${_t("threads|show_thread_filter")} ${value?.label}`} +
+ {contextMenu} + + )} +
+ ); }; diff --git a/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap b/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap index b395e603a60..838414f72b0 100644 --- a/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap +++ b/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap @@ -10,6 +10,24 @@ exports[`ThreadPanel Header expect that All filter for ThreadPanelHeader properl > Threads + +