Add notification dots to thread summary icons (#12146)
* Add notification dots to thread summary icons Adopts new IndicatorIcon from compound to have threads icons with indicator dot (that aren't also buttons). Adds green & red dots on the threads icon in the thread summary to indicate notifications. Changes the notification level dots colours in the threads panel to be green to match. * Update test for new CSS class * Update snapshots with new class name * Another snapshot update for new class name * Replace more uses of old class name in tests * More snapshot updates for new class name * Unsure how this ever worked in chronological mode * More snapshot updates * Fix dot colours * Upgrade to compound-web 3 * Fix computed notification levels * Add test for notificationLevelToIndicator
This commit is contained in:
parent
f684ad51cd
commit
95430cecbc
19 changed files with 130 additions and 54 deletions
|
@ -74,7 +74,7 @@
|
||||||
"@sentry/browser": "^7.0.0",
|
"@sentry/browser": "^7.0.0",
|
||||||
"@testing-library/react-hooks": "^8.0.1",
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
"@vector-im/compound-design-tokens": "^0.1.0",
|
"@vector-im/compound-design-tokens": "^0.1.0",
|
||||||
"@vector-im/compound-web": "2.0.0",
|
"@vector-im/compound-web": "3.0.0",
|
||||||
"@zxcvbn-ts/core": "^3.0.4",
|
"@zxcvbn-ts/core": "^3.0.4",
|
||||||
"@zxcvbn-ts/language-common": "^3.0.4",
|
"@zxcvbn-ts/language-common": "^3.0.4",
|
||||||
"@zxcvbn-ts/language-en": "^3.0.2",
|
"@zxcvbn-ts/language-en": "^3.0.2",
|
||||||
|
|
|
@ -33,21 +33,34 @@ limitations under the License.
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
&.mx_NotificationBadge_highlighted {
|
|
||||||
/* TODO: Use a more specific variable */
|
|
||||||
background-color: $alert;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These are the 3 background types */
|
/* These are the 3 background types */
|
||||||
|
|
||||||
&.mx_NotificationBadge_dot {
|
&.mx_NotificationBadge_dot {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
background-color: var(--cpd-color-text-primary);
|
||||||
|
|
||||||
.mx_NotificationBadge_count {
|
.mx_NotificationBadge_count {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Redundant sounding name, but a notification badge that indicates there is a regular,
|
||||||
|
* non-highlight notification
|
||||||
|
* The green colour only applies for notification dot: badges indicating the same notification
|
||||||
|
* level are the standard grey.
|
||||||
|
*/
|
||||||
|
&.mx_NotificationBadge_level_notification {
|
||||||
|
background-color: var(--cpd-color-icon-success-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Badges for highlight notifications. Style for notification level
|
||||||
|
* badges is in _EventTile.scss because it applies only to notification
|
||||||
|
* dots, not badges.
|
||||||
|
*/
|
||||||
|
&.mx_NotificationBadge_level_highlight {
|
||||||
|
background-color: var(--cpd-color-icon-critical-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_NotificationBadge_knocked {
|
&.mx_NotificationBadge_knocked {
|
||||||
|
|
|
@ -59,7 +59,8 @@ export const StatelessNotificationBadge = forwardRef<HTMLDivElement, XOR<Props,
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
mx_NotificationBadge: true,
|
mx_NotificationBadge: true,
|
||||||
mx_NotificationBadge_visible: isEmptyBadge || knocked ? true : hasUnreadCount,
|
mx_NotificationBadge_visible: isEmptyBadge || knocked ? true : hasUnreadCount,
|
||||||
mx_NotificationBadge_highlighted: level >= NotificationLevel.Highlight,
|
mx_NotificationBadge_level_notification: level == NotificationLevel.Notification,
|
||||||
|
mx_NotificationBadge_level_highlight: level >= NotificationLevel.Highlight,
|
||||||
mx_NotificationBadge_dot: (isEmptyBadge && !knocked) || type === "dot",
|
mx_NotificationBadge_dot: (isEmptyBadge && !knocked) || type === "dot",
|
||||||
mx_NotificationBadge_knocked: knocked,
|
mx_NotificationBadge_knocked: knocked,
|
||||||
mx_NotificationBadge_2char: type === "badge" && symbol && symbol.length > 0 && symbol.length < 3,
|
mx_NotificationBadge_2char: type === "badge" && symbol && symbol.length > 0 && symbol.length < 3,
|
||||||
|
|
|
@ -37,7 +37,6 @@ import { Flex } from "../../utils/Flex";
|
||||||
import { Box } from "../../utils/Box";
|
import { Box } from "../../utils/Box";
|
||||||
import { useRoomCall } from "../../../hooks/room/useRoomCall";
|
import { useRoomCall } from "../../../hooks/room/useRoomCall";
|
||||||
import { useRoomThreadNotifications } from "../../../hooks/room/useRoomThreadNotifications";
|
import { useRoomThreadNotifications } from "../../../hooks/room/useRoomThreadNotifications";
|
||||||
import { NotificationLevel } from "../../../stores/notifications/NotificationLevel";
|
|
||||||
import { useGlobalNotificationState } from "../../../hooks/useGlobalNotificationState";
|
import { useGlobalNotificationState } from "../../../hooks/useGlobalNotificationState";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
||||||
|
@ -52,20 +51,7 @@ import { Linkify, topicToHtml } from "../../../HtmlUtils";
|
||||||
import PosthogTrackers from "../../../PosthogTrackers";
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
import { VideoRoomChatButton } from "./RoomHeader/VideoRoomChatButton";
|
import { VideoRoomChatButton } from "./RoomHeader/VideoRoomChatButton";
|
||||||
import { RoomKnocksBar } from "./RoomKnocksBar";
|
import { RoomKnocksBar } from "./RoomKnocksBar";
|
||||||
|
import { notificationLevelToIndicator } from "../../../utils/notifications";
|
||||||
/**
|
|
||||||
* A helper to transform a notification color to the what the Compound Icon Button
|
|
||||||
* expects
|
|
||||||
*/
|
|
||||||
function notificationLevelToIndicator(color: NotificationLevel): React.ComponentProps<typeof IconButton>["indicator"] {
|
|
||||||
if (color <= NotificationLevel.None) {
|
|
||||||
return undefined;
|
|
||||||
} else if (color <= NotificationLevel.Notification) {
|
|
||||||
return "default";
|
|
||||||
} else {
|
|
||||||
return "highlight";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function RoomHeader({
|
export default function RoomHeader({
|
||||||
room,
|
room,
|
||||||
|
|
|
@ -16,6 +16,8 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { Thread, ThreadEvent, IContent, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/matrix";
|
import { Thread, ThreadEvent, IContent, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { IndicatorIcon } from "@vector-im/compound-web";
|
||||||
|
import { Icon as ThreadIconSolid } from "@vector-im/compound-design-tokens/icons/threads-solid.svg";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { CardContext } from "../right_panel/context";
|
import { CardContext } from "../right_panel/context";
|
||||||
|
@ -30,6 +32,8 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
|
import { useUnreadNotifications } from "../../../hooks/useUnreadNotifications";
|
||||||
|
import { notificationLevelToIndicator } from "../../../utils/notifications";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -40,6 +44,8 @@ const ThreadSummary: React.FC<IProps> = ({ mxEvent, thread, ...props }) => {
|
||||||
const roomContext = useContext(RoomContext);
|
const roomContext = useContext(RoomContext);
|
||||||
const cardContext = useContext(CardContext);
|
const cardContext = useContext(CardContext);
|
||||||
const count = useTypedEventEmitterState(thread, ThreadEvent.Update, () => thread.length);
|
const count = useTypedEventEmitterState(thread, ThreadEvent.Update, () => thread.length);
|
||||||
|
const { level } = useUnreadNotifications(thread.room, thread.id);
|
||||||
|
|
||||||
if (!count) return null; // We don't want to show a thread summary if the thread doesn't have replies yet
|
if (!count) return null; // We don't want to show a thread summary if the thread doesn't have replies yet
|
||||||
|
|
||||||
let countSection: string | number = count;
|
let countSection: string | number = count;
|
||||||
|
@ -61,6 +67,9 @@ const ThreadSummary: React.FC<IProps> = ({ mxEvent, thread, ...props }) => {
|
||||||
}}
|
}}
|
||||||
aria-label={_t("threads|open_thread")}
|
aria-label={_t("threads|open_thread")}
|
||||||
>
|
>
|
||||||
|
<IndicatorIcon size="24px" indicator={notificationLevelToIndicator(level)}>
|
||||||
|
<ThreadIconSolid />
|
||||||
|
</IndicatorIcon>
|
||||||
<span className="mx_ThreadSummary_replies_amount">{countSection}</span>
|
<span className="mx_ThreadSummary_replies_amount">{countSection}</span>
|
||||||
<ThreadMessagePreview thread={thread} showDisplayname={!roomContext.narrow} />
|
<ThreadMessagePreview thread={thread} showDisplayname={!roomContext.narrow} />
|
||||||
<div className="mx_ThreadSummary_chevron" />
|
<div className="mx_ThreadSummary_chevron" />
|
||||||
|
|
|
@ -33,10 +33,10 @@ export const useRoomThreadNotifications = (room: Room): NotificationLevel => {
|
||||||
switch (room?.threadsAggregateNotificationType) {
|
switch (room?.threadsAggregateNotificationType) {
|
||||||
case NotificationCountType.Highlight:
|
case NotificationCountType.Highlight:
|
||||||
setNotificationLevel(NotificationLevel.Highlight);
|
setNotificationLevel(NotificationLevel.Highlight);
|
||||||
break;
|
return;
|
||||||
case NotificationCountType.Total:
|
case NotificationCountType.Total:
|
||||||
setNotificationLevel(NotificationLevel.Notification);
|
setNotificationLevel(NotificationLevel.Notification);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
// We don't have any notified messages, but we might have unread messages. Let's
|
// We don't have any notified messages, but we might have unread messages. Let's
|
||||||
// find out.
|
// find out.
|
||||||
|
|
|
@ -22,8 +22,10 @@ import {
|
||||||
LocalNotificationSettings,
|
LocalNotificationSettings,
|
||||||
ReceiptType,
|
ReceiptType,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
|
import { IndicatorIcon } from "@vector-im/compound-web";
|
||||||
|
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
|
import { NotificationLevel } from "../stores/notifications/NotificationLevel";
|
||||||
|
|
||||||
export const deviceNotificationSettingsKeys = [
|
export const deviceNotificationSettingsKeys = [
|
||||||
"notificationsEnabled",
|
"notificationsEnabled",
|
||||||
|
@ -113,3 +115,21 @@ export function clearAllNotifications(client: MatrixClient): Promise<Array<{} |
|
||||||
|
|
||||||
return Promise.all(receiptPromises);
|
return Promise.all(receiptPromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper to transform a notification color to the what the Compound Icon Button
|
||||||
|
* expects
|
||||||
|
*/
|
||||||
|
export function notificationLevelToIndicator(
|
||||||
|
level: NotificationLevel,
|
||||||
|
): React.ComponentPropsWithRef<typeof IndicatorIcon>["indicator"] {
|
||||||
|
if (level <= NotificationLevel.None) {
|
||||||
|
return undefined;
|
||||||
|
} else if (level <= NotificationLevel.Activity) {
|
||||||
|
return "default";
|
||||||
|
} else if (level <= NotificationLevel.Notification) {
|
||||||
|
return "success";
|
||||||
|
} else {
|
||||||
|
return "critical";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -817,7 +817,7 @@ describe("TimelinePanel", () => {
|
||||||
client = MatrixClientPeg.safeGet();
|
client = MatrixClientPeg.safeGet();
|
||||||
|
|
||||||
Thread.hasServerSideSupport = FeatureSupport.Stable;
|
Thread.hasServerSideSupport = FeatureSupport.Stable;
|
||||||
room = new Room("roomId", client, "userId");
|
room = new Room("roomId", client, "userId", { pendingEventOrdering: PendingEventOrdering.Detached });
|
||||||
allThreads = new EventTimelineSet(
|
allThreads = new EventTimelineSet(
|
||||||
room,
|
room,
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@ exports[`RoomStatusBar <RoomStatusBar /> unsent messages should render warning w
|
||||||
class="mx_RoomStatusBar_unsentBadge"
|
class="mx_RoomStatusBar_unsentBadge"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_highlighted mx_NotificationBadge_2char"
|
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_level_highlight mx_NotificationBadge_2char"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="mx_NotificationBadge_count"
|
class="mx_NotificationBadge_count"
|
||||||
|
@ -81,7 +81,7 @@ exports[`RoomStatusBar <RoomStatusBar /> unsent messages should render warning w
|
||||||
class="mx_RoomStatusBar_unsentBadge"
|
class="mx_RoomStatusBar_unsentBadge"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_highlighted mx_NotificationBadge_2char"
|
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_level_highlight mx_NotificationBadge_2char"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="mx_NotificationBadge_count"
|
class="mx_NotificationBadge_count"
|
||||||
|
|
|
@ -215,7 +215,7 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
|
||||||
class="mx_RoomStatusBar_unsentBadge"
|
class="mx_RoomStatusBar_unsentBadge"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_highlighted mx_NotificationBadge_2char"
|
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_level_highlight mx_NotificationBadge_2char"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="mx_NotificationBadge_count"
|
class="mx_NotificationBadge_count"
|
||||||
|
|
|
@ -163,14 +163,14 @@ describe("EventTile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1);
|
expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1);
|
||||||
expect(container.getElementsByClassName("mx_NotificationBadge_highlighted")).toHaveLength(0);
|
expect(container.getElementsByClassName("mx_NotificationBadge_level_highlight")).toHaveLength(0);
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
room.setThreadUnreadNotificationCount(mxEvent.getId()!, NotificationCountType.Highlight, 1);
|
room.setThreadUnreadNotificationCount(mxEvent.getId()!, NotificationCountType.Highlight, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1);
|
expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1);
|
||||||
expect(container.getElementsByClassName("mx_NotificationBadge_highlighted")).toHaveLength(1);
|
expect(container.getElementsByClassName("mx_NotificationBadge_level_highlight")).toHaveLength(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe("StatelessNotificationBadge", () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<StatelessNotificationBadge symbol="!" count={0} level={NotificationLevel.Unsent} />,
|
<StatelessNotificationBadge symbol="!" count={0} level={NotificationLevel.Unsent} />,
|
||||||
);
|
);
|
||||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).not.toBe(null);
|
expect(container.querySelector(".mx_NotificationBadge_level_highlight")).not.toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has knock style", () => {
|
it("has knock style", () => {
|
||||||
|
|
|
@ -92,26 +92,26 @@ describe("UnreadNotificationBadge", () => {
|
||||||
const { container } = render(getComponent());
|
const { container } = render(getComponent());
|
||||||
|
|
||||||
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
|
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
|
||||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).toBeFalsy();
|
expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeFalsy();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
room.setUnreadNotificationCount(NotificationCountType.Highlight, 1);
|
room.setUnreadNotificationCount(NotificationCountType.Highlight, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).toBeTruthy();
|
expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders unread thread notification badge", () => {
|
it("renders unread thread notification badge", () => {
|
||||||
const { container } = render(getComponent(THREAD_ID));
|
const { container } = render(getComponent(THREAD_ID));
|
||||||
|
|
||||||
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
|
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
|
||||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).toBeFalsy();
|
expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeFalsy();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 1);
|
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).toBeTruthy();
|
expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("hides unread notification badge", () => {
|
it("hides unread notification badge", () => {
|
||||||
|
@ -177,6 +177,6 @@ describe("UnreadNotificationBadge", () => {
|
||||||
const { container } = render(getComponent(THREAD_ID));
|
const { container } = render(getComponent(THREAD_ID));
|
||||||
expect(container.querySelector(".mx_NotificationBadge_dot")).toBeTruthy();
|
expect(container.querySelector(".mx_NotificationBadge_dot")).toBeTruthy();
|
||||||
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
|
expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy();
|
||||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).toBeFalsy();
|
expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,26 +3,37 @@
|
||||||
exports[`<VideoRoomChatButton /> renders button when room is a video room 1`] = `
|
exports[`<VideoRoomChatButton /> renders button when room is a video room 1`] = `
|
||||||
<button
|
<button
|
||||||
aria-label="Chat"
|
aria-label="Chat"
|
||||||
class="_icon-button_ur2sw_17"
|
class="_icon-button_16nk7_17"
|
||||||
data-state="closed"
|
data-state="closed"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div />
|
<div
|
||||||
|
class="_indicator-icon_jtb4d_26"
|
||||||
|
style="--cpd-icon-button-size: 100%;"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<VideoRoomChatButton /> renders button with an unread marker when room is unread 1`] = `
|
exports[`<VideoRoomChatButton /> renders button with an unread marker when room is unread 1`] = `
|
||||||
<button
|
<button
|
||||||
aria-label="Chat"
|
aria-label="Chat"
|
||||||
class="_icon-button_ur2sw_17"
|
class="_icon-button_16nk7_17"
|
||||||
data-indicator="default"
|
data-indicator="default"
|
||||||
data-state="closed"
|
data-state="closed"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div />
|
<div
|
||||||
|
class="_indicator-icon_jtb4d_26"
|
||||||
|
data-indicator="default"
|
||||||
|
style="--cpd-icon-button-size: 100%;"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -46,34 +46,49 @@ exports[`RoomHeader does not show the face pile for DMs 1`] = `
|
||||||
<button
|
<button
|
||||||
aria-disabled="true"
|
aria-disabled="true"
|
||||||
aria-label="There's no one here to call"
|
aria-label="There's no one here to call"
|
||||||
class="_icon-button_ur2sw_17"
|
class="_icon-button_16nk7_17"
|
||||||
data-state="closed"
|
data-state="closed"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div />
|
<div
|
||||||
|
class="_indicator-icon_jtb4d_26"
|
||||||
|
style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-disabled="true"
|
aria-disabled="true"
|
||||||
aria-label="There's no one here to call"
|
aria-label="There's no one here to call"
|
||||||
class="_icon-button_ur2sw_17"
|
class="_icon-button_16nk7_17"
|
||||||
data-state="closed"
|
data-state="closed"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div />
|
<div
|
||||||
|
class="_indicator-icon_jtb4d_26"
|
||||||
|
style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-label="Threads"
|
aria-label="Threads"
|
||||||
class="_icon-button_ur2sw_17"
|
class="_icon-button_16nk7_17"
|
||||||
data-state="closed"
|
data-state="closed"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div />
|
<div
|
||||||
|
class="_indicator-icon_jtb4d_26"
|
||||||
|
style="--cpd-icon-button-size: 100%;"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -480,7 +480,7 @@ exports[`<Notifications /> correctly handles the loading/disabled state 1`] = `
|
||||||
<span>
|
<span>
|
||||||
Show a badge
|
Show a badge
|
||||||
<div
|
<div
|
||||||
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_2char"
|
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_level_notification mx_NotificationBadge_2char"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="mx_NotificationBadge_count"
|
class="mx_NotificationBadge_count"
|
||||||
|
@ -1190,7 +1190,7 @@ exports[`<Notifications /> matches the snapshot 1`] = `
|
||||||
<span>
|
<span>
|
||||||
Show a badge
|
Show a badge
|
||||||
<div
|
<div
|
||||||
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_2char"
|
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_level_notification mx_NotificationBadge_2char"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="mx_NotificationBadge_count"
|
class="mx_NotificationBadge_count"
|
||||||
|
|
|
@ -26,7 +26,7 @@ exports[`SpaceButton metaspace should render notificationState if one is provide
|
||||||
class="mx_SpacePanel_badgeContainer"
|
class="mx_SpacePanel_badgeContainer"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_AccessibleButton mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_2char"
|
class="mx_AccessibleButton mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_level_notification mx_NotificationBadge_2char"
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
>
|
>
|
||||||
|
|
|
@ -24,11 +24,13 @@ import {
|
||||||
deviceNotificationSettingsKeys,
|
deviceNotificationSettingsKeys,
|
||||||
clearAllNotifications,
|
clearAllNotifications,
|
||||||
clearRoomNotification,
|
clearRoomNotification,
|
||||||
|
notificationLevelToIndicator,
|
||||||
} from "../../src/utils/notifications";
|
} from "../../src/utils/notifications";
|
||||||
import SettingsStore from "../../src/settings/SettingsStore";
|
import SettingsStore from "../../src/settings/SettingsStore";
|
||||||
import { getMockClientWithEventEmitter } from "../test-utils/client";
|
import { getMockClientWithEventEmitter } from "../test-utils/client";
|
||||||
import { mkMessage, stubClient } from "../test-utils/test-utils";
|
import { mkMessage, stubClient } from "../test-utils/test-utils";
|
||||||
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||||
|
import { NotificationLevel } from "../../src/stores/notifications/NotificationLevel";
|
||||||
|
|
||||||
jest.mock("../../src/settings/SettingsStore");
|
jest.mock("../../src/settings/SettingsStore");
|
||||||
|
|
||||||
|
@ -215,4 +217,22 @@ describe("notifications", () => {
|
||||||
expect(sendReadReceiptSpy).toHaveBeenCalledWith(message, ReceiptType.ReadPrivate, true);
|
expect(sendReadReceiptSpy).toHaveBeenCalledWith(message, ReceiptType.ReadPrivate, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("notificationLevelToIndicator", () => {
|
||||||
|
it("returns undefined if notification level is None", () => {
|
||||||
|
expect(notificationLevelToIndicator(NotificationLevel.None)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns default if notification level is Activity", () => {
|
||||||
|
expect(notificationLevelToIndicator(NotificationLevel.Activity)).toEqual("default");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns success if notification level is Notification", () => {
|
||||||
|
expect(notificationLevelToIndicator(NotificationLevel.Notification)).toEqual("success");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns critical if notification level is Highlight", () => {
|
||||||
|
expect(notificationLevelToIndicator(NotificationLevel.Highlight)).toEqual("critical");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
11
yarn.lock
11
yarn.lock
|
@ -2276,7 +2276,7 @@
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-primitive" "1.0.3"
|
"@radix-ui/react-primitive" "1.0.3"
|
||||||
|
|
||||||
"@radix-ui/react-slot@1.0.2":
|
"@radix-ui/react-slot@1.0.2", "@radix-ui/react-slot@^1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
||||||
integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
|
integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
|
||||||
|
@ -3120,15 +3120,16 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
svg2vectordrawable "^2.9.1"
|
svg2vectordrawable "^2.9.1"
|
||||||
|
|
||||||
"@vector-im/compound-web@2.0.0":
|
"@vector-im/compound-web@3.0.0":
|
||||||
version "2.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-2.0.0.tgz#9ffc621f32be11acabe74bb3ff59cc4d8bc845ac"
|
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-3.0.0.tgz#8843c1c6a40891f89fdb3dbccf972e2fc2e1e387"
|
||||||
integrity sha512-vEhGayoBSq4WLf86VmFoX9h0KIxaAjlG+kmcJLWitsqnPEDOG0XPhScYqzEshFqdJFLWX6gBOnXYLeq065t57w==
|
integrity sha512-6wkFoByaiXvwrqNmF0W9K5/krThpczPnYeJOBG3FM90RoC3MrqNB6fBPTvsd17pzJWN6fEV2B11JUeqAFW0z5A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@radix-ui/react-context-menu" "^2.1.5"
|
"@radix-ui/react-context-menu" "^2.1.5"
|
||||||
"@radix-ui/react-dropdown-menu" "^2.0.6"
|
"@radix-ui/react-dropdown-menu" "^2.0.6"
|
||||||
"@radix-ui/react-form" "^0.0.3"
|
"@radix-ui/react-form" "^0.0.3"
|
||||||
"@radix-ui/react-separator" "^1.0.3"
|
"@radix-ui/react-separator" "^1.0.3"
|
||||||
|
"@radix-ui/react-slot" "^1.0.2"
|
||||||
"@radix-ui/react-tooltip" "^1.0.6"
|
"@radix-ui/react-tooltip" "^1.0.6"
|
||||||
classnames "^2.3.2"
|
classnames "^2.3.2"
|
||||||
graphemer "^1.4.0"
|
graphemer "^1.4.0"
|
||||||
|
|
Loading…
Reference in a new issue