Devtools for stuck notifications (#10042)
This commit is contained in:
parent
469228f45e
commit
6dd578e5a7
9 changed files with 378 additions and 6 deletions
|
@ -33,6 +33,7 @@ import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
import ServerInfo from "./devtools/ServerInfo";
|
import ServerInfo from "./devtools/ServerInfo";
|
||||||
import { Features } from "../../../settings/Settings";
|
import { Features } from "../../../settings/Settings";
|
||||||
import CopyableText from "../elements/CopyableText";
|
import CopyableText from "../elements/CopyableText";
|
||||||
|
import RoomNotifications from "./devtools/RoomNotifications";
|
||||||
|
|
||||||
enum Category {
|
enum Category {
|
||||||
Room,
|
Room,
|
||||||
|
@ -44,13 +45,14 @@ const categoryLabels: Record<Category, string> = {
|
||||||
[Category.Other]: _td("Other"),
|
[Category.Other]: _td("Other"),
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Tool = React.FC<IDevtoolsProps>;
|
export type Tool = React.FC<IDevtoolsProps> | ((props: IDevtoolsProps) => JSX.Element);
|
||||||
const Tools: Record<Category, [label: string, tool: Tool][]> = {
|
const Tools: Record<Category, [label: string, tool: Tool][]> = {
|
||||||
[Category.Room]: [
|
[Category.Room]: [
|
||||||
[_td("Send custom timeline event"), TimelineEventEditor],
|
[_td("Send custom timeline event"), TimelineEventEditor],
|
||||||
[_td("Explore room state"), RoomStateExplorer],
|
[_td("Explore room state"), RoomStateExplorer],
|
||||||
[_td("Explore room account data"), RoomAccountDataExplorer],
|
[_td("Explore room account data"), RoomAccountDataExplorer],
|
||||||
[_td("View servers in room"), ServersInRoom],
|
[_td("View servers in room"), ServersInRoom],
|
||||||
|
[_td("Notifications debug"), RoomNotifications],
|
||||||
[_td("Verification explorer"), VerificationExplorer],
|
[_td("Verification explorer"), VerificationExplorer],
|
||||||
[_td("Active Widgets"), WidgetExplorer],
|
[_td("Active Widgets"), WidgetExplorer],
|
||||||
],
|
],
|
||||||
|
|
180
src/components/views/dialogs/devtools/RoomNotifications.tsx
Normal file
180
src/components/views/dialogs/devtools/RoomNotifications.tsx
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { Thread } from "matrix-js-sdk/src/models/thread";
|
||||||
|
import React, { useContext } from "react";
|
||||||
|
|
||||||
|
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
||||||
|
import { useNotificationState } from "../../../../hooks/useRoomNotificationState";
|
||||||
|
import { _t } from "../../../../languageHandler";
|
||||||
|
import { determineUnreadState } from "../../../../RoomNotifs";
|
||||||
|
import { humanReadableNotificationColor } from "../../../../stores/notifications/NotificationColor";
|
||||||
|
import { doesRoomOrThreadHaveUnreadMessages } from "../../../../Unread";
|
||||||
|
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
||||||
|
|
||||||
|
export default function RoomNotifications({ onBack }: IDevtoolsProps): JSX.Element {
|
||||||
|
const { room } = useContext(DevtoolsContext);
|
||||||
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
|
const { color, count } = determineUnreadState(room);
|
||||||
|
const [notificationState] = useNotificationState(room);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseTool onBack={onBack}>
|
||||||
|
<section>
|
||||||
|
<h2>{_t("Room status")}</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{_t("Room unread status: ")}
|
||||||
|
<strong>{humanReadableNotificationColor(color)}</strong>
|
||||||
|
{count > 0 && (
|
||||||
|
<>
|
||||||
|
{_t(", count:")} <strong>{count}</strong>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Notification state is")} <strong>{notificationState}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Room is ")}
|
||||||
|
<strong>
|
||||||
|
{cli.isRoomEncrypted(room.roomId!) ? _t("encrypted ✅") : _t("not encrypted 🚨")}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>{_t("Main timeline")}</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{_t("Total: ")} {room.getRoomUnreadNotificationCount(NotificationCountType.Total)}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Highlight: ")} {room.getRoomUnreadNotificationCount(NotificationCountType.Highlight)}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Dot: ")} {doesRoomOrThreadHaveUnreadMessages(room) + ""}
|
||||||
|
</li>
|
||||||
|
{roomHasUnread(room) && (
|
||||||
|
<>
|
||||||
|
<li>
|
||||||
|
{_t("User read up to: ")}
|
||||||
|
<strong>
|
||||||
|
{room.getReadReceiptForUserId(cli.getSafeUserId())?.eventId ??
|
||||||
|
_t("No receipt found")}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Last event:")}
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{_t("ID: ")} <strong>{room.timeline[room.timeline.length - 1].getId()}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Type: ")}{" "}
|
||||||
|
<strong>{room.timeline[room.timeline.length - 1].getType()}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Sender: ")}{" "}
|
||||||
|
<strong>{room.timeline[room.timeline.length - 1].getSender()}</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>{_t("Threads timeline")}</h2>
|
||||||
|
<ul>
|
||||||
|
{room
|
||||||
|
.getThreads()
|
||||||
|
.filter((thread) => threadHasUnread(thread))
|
||||||
|
.map((thread) => (
|
||||||
|
<li key={thread.id}>
|
||||||
|
{_t("Thread Id: ")} {thread.id}
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{_t("Total: ")}
|
||||||
|
<strong>
|
||||||
|
{room.getThreadUnreadNotificationCount(
|
||||||
|
thread.id,
|
||||||
|
NotificationCountType.Total,
|
||||||
|
)}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Highlight: ")}
|
||||||
|
<strong>
|
||||||
|
{room.getThreadUnreadNotificationCount(
|
||||||
|
thread.id,
|
||||||
|
NotificationCountType.Highlight,
|
||||||
|
)}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Dot: ")} <strong>{doesRoomOrThreadHaveUnreadMessages(thread) + ""}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("User read up to: ")}
|
||||||
|
<strong>
|
||||||
|
{thread.getReadReceiptForUserId(cli.getSafeUserId())?.eventId ??
|
||||||
|
_t("No receipt found")}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Last event:")}
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{_t("ID: ")} <strong>{thread.lastReply()?.getId()}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Type: ")} <strong>{thread.lastReply()?.getType()}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("Sender: ")} <strong>{thread.lastReply()?.getSender()}</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</BaseTool>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function threadHasUnread(thread: Thread): boolean {
|
||||||
|
const total = thread.room.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Total);
|
||||||
|
const highlight = thread.room.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Highlight);
|
||||||
|
const dot = doesRoomOrThreadHaveUnreadMessages(thread);
|
||||||
|
|
||||||
|
return total > 0 || highlight > 0 || dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
function roomHasUnread(room: Room): boolean {
|
||||||
|
const total = room.getRoomUnreadNotificationCount(NotificationCountType.Total);
|
||||||
|
const highlight = room.getRoomUnreadNotificationCount(NotificationCountType.Highlight);
|
||||||
|
const dot = doesRoomOrThreadHaveUnreadMessages(room);
|
||||||
|
|
||||||
|
return total > 0 || highlight > 0 || dot;
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||||
import { useTypedEventEmitter, useTypedEventEmitterState } from "../../../../hooks/useEventEmitter";
|
import { useTypedEventEmitter, useTypedEventEmitterState } from "../../../../hooks/useEventEmitter";
|
||||||
import { _t, _td } from "../../../../languageHandler";
|
import { _t, _td } from "../../../../languageHandler";
|
||||||
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
||||||
import BaseTool, { DevtoolsContext } from "./BaseTool";
|
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
||||||
import { Tool } from "../DevtoolsDialog";
|
import { Tool } from "../DevtoolsDialog";
|
||||||
|
|
||||||
const PHASE_MAP: Record<Phase, string> = {
|
const PHASE_MAP: Record<Phase, string> = {
|
||||||
|
@ -81,7 +81,7 @@ const VerificationRequestExplorer: React.FC<{
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const VerificationExplorer: Tool = ({ onBack }) => {
|
const VerificationExplorer: Tool = ({ onBack }: IDevtoolsProps) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
const context = useContext(DevtoolsContext);
|
const context = useContext(DevtoolsContext);
|
||||||
|
|
||||||
|
|
|
@ -902,6 +902,12 @@
|
||||||
"Room information": "Room information",
|
"Room information": "Room information",
|
||||||
"Room members": "Room members",
|
"Room members": "Room members",
|
||||||
"Back to thread": "Back to thread",
|
"Back to thread": "Back to thread",
|
||||||
|
"None": "None",
|
||||||
|
"Bold": "Bold",
|
||||||
|
"Grey": "Grey",
|
||||||
|
"Red": "Red",
|
||||||
|
"Unsent": "Unsent",
|
||||||
|
"unknown": "unknown",
|
||||||
"Change notification settings": "Change notification settings",
|
"Change notification settings": "Change notification settings",
|
||||||
"Messaging": "Messaging",
|
"Messaging": "Messaging",
|
||||||
"Profile": "Profile",
|
"Profile": "Profile",
|
||||||
|
@ -1582,7 +1588,6 @@
|
||||||
"Error removing ignored user/server": "Error removing ignored user/server",
|
"Error removing ignored user/server": "Error removing ignored user/server",
|
||||||
"Error unsubscribing from list": "Error unsubscribing from list",
|
"Error unsubscribing from list": "Error unsubscribing from list",
|
||||||
"Please try again or view your console for hints.": "Please try again or view your console for hints.",
|
"Please try again or view your console for hints.": "Please try again or view your console for hints.",
|
||||||
"None": "None",
|
|
||||||
"Ban list rules - %(roomName)s": "Ban list rules - %(roomName)s",
|
"Ban list rules - %(roomName)s": "Ban list rules - %(roomName)s",
|
||||||
"Server rules": "Server rules",
|
"Server rules": "Server rules",
|
||||||
"User rules": "User rules",
|
"User rules": "User rules",
|
||||||
|
@ -1942,7 +1947,6 @@
|
||||||
"Poll": "Poll",
|
"Poll": "Poll",
|
||||||
"Hide formatting": "Hide formatting",
|
"Hide formatting": "Hide formatting",
|
||||||
"Show formatting": "Show formatting",
|
"Show formatting": "Show formatting",
|
||||||
"Bold": "Bold",
|
|
||||||
"Italics": "Italics",
|
"Italics": "Italics",
|
||||||
"Strikethrough": "Strikethrough",
|
"Strikethrough": "Strikethrough",
|
||||||
"Code block": "Code block",
|
"Code block": "Code block",
|
||||||
|
@ -2773,6 +2777,7 @@
|
||||||
"Explore room state": "Explore room state",
|
"Explore room state": "Explore room state",
|
||||||
"Explore room account data": "Explore room account data",
|
"Explore room account data": "Explore room account data",
|
||||||
"View servers in room": "View servers in room",
|
"View servers in room": "View servers in room",
|
||||||
|
"Notifications debug": "Notifications debug",
|
||||||
"Verification explorer": "Verification explorer",
|
"Verification explorer": "Verification explorer",
|
||||||
"Active Widgets": "Active Widgets",
|
"Active Widgets": "Active Widgets",
|
||||||
"Explore account data": "Explore account data",
|
"Explore account data": "Explore account data",
|
||||||
|
@ -3152,6 +3157,25 @@
|
||||||
"Event Content": "Event Content",
|
"Event Content": "Event Content",
|
||||||
"Filter results": "Filter results",
|
"Filter results": "Filter results",
|
||||||
"No results found": "No results found",
|
"No results found": "No results found",
|
||||||
|
"Room status": "Room status",
|
||||||
|
"Room unread status: ": "Room unread status: ",
|
||||||
|
", count:": ", count:",
|
||||||
|
"Notification state is": "Notification state is",
|
||||||
|
"Room is ": "Room is ",
|
||||||
|
"encrypted ✅": "encrypted ✅",
|
||||||
|
"not encrypted 🚨": "not encrypted 🚨",
|
||||||
|
"Main timeline": "Main timeline",
|
||||||
|
"Total: ": "Total: ",
|
||||||
|
"Highlight: ": "Highlight: ",
|
||||||
|
"Dot: ": "Dot: ",
|
||||||
|
"User read up to: ": "User read up to: ",
|
||||||
|
"No receipt found": "No receipt found",
|
||||||
|
"Last event:": "Last event:",
|
||||||
|
"ID: ": "ID: ",
|
||||||
|
"Type: ": "Type: ",
|
||||||
|
"Sender: ": "Sender: ",
|
||||||
|
"Threads timeline": "Threads timeline",
|
||||||
|
"Thread Id: ": "Thread Id: ",
|
||||||
"<%(count)s spaces>|other": "<%(count)s spaces>",
|
"<%(count)s spaces>|other": "<%(count)s spaces>",
|
||||||
"<%(count)s spaces>|one": "<space>",
|
"<%(count)s spaces>|one": "<space>",
|
||||||
"<%(count)s spaces>|zero": "<empty string>",
|
"<%(count)s spaces>|zero": "<empty string>",
|
||||||
|
@ -3182,7 +3206,6 @@
|
||||||
"Value": "Value",
|
"Value": "Value",
|
||||||
"Value in this room": "Value in this room",
|
"Value in this room": "Value in this room",
|
||||||
"Edit setting": "Edit setting",
|
"Edit setting": "Edit setting",
|
||||||
"Unsent": "Unsent",
|
|
||||||
"Requested": "Requested",
|
"Requested": "Requested",
|
||||||
"Ready": "Ready",
|
"Ready": "Ready",
|
||||||
"Started": "Started",
|
"Started": "Started",
|
||||||
|
|
|
@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { _t } from "../../languageHandler";
|
||||||
|
|
||||||
export enum NotificationColor {
|
export enum NotificationColor {
|
||||||
// Inverted (None -> Red) because we do integer comparisons on this
|
// Inverted (None -> Red) because we do integer comparisons on this
|
||||||
None, // nothing special
|
None, // nothing special
|
||||||
|
@ -23,3 +25,20 @@ export enum NotificationColor {
|
||||||
Red, // unread pings
|
Red, // unread pings
|
||||||
Unsent, // some messages failed to send
|
Unsent, // some messages failed to send
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function humanReadableNotificationColor(color: NotificationColor): string {
|
||||||
|
switch (color) {
|
||||||
|
case NotificationColor.None:
|
||||||
|
return _t("None");
|
||||||
|
case NotificationColor.Bold:
|
||||||
|
return _t("Bold");
|
||||||
|
case NotificationColor.Grey:
|
||||||
|
return _t("Grey");
|
||||||
|
case NotificationColor.Red:
|
||||||
|
return _t("Red");
|
||||||
|
case NotificationColor.Unsent:
|
||||||
|
return _t("Unsent");
|
||||||
|
default:
|
||||||
|
return _t("unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -75,6 +75,11 @@ exports[`DevtoolsDialog renders the devtools dialog 1`] = `
|
||||||
>
|
>
|
||||||
View servers in room
|
View servers in room
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="mx_DevTools_button"
|
||||||
|
>
|
||||||
|
Notifications debug
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="mx_DevTools_button"
|
class="mx_DevTools_button"
|
||||||
>
|
>
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { PendingEventOrdering } from "matrix-js-sdk/src/client";
|
||||||
|
|
||||||
|
import RoomNotifications from "../../../../../src/components/views/dialogs/devtools/RoomNotifications";
|
||||||
|
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
|
||||||
|
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
|
||||||
|
import { stubClient } from "../../../../test-utils";
|
||||||
|
import { DevtoolsContext } from "../../../../../src/components/views/dialogs/devtools/BaseTool";
|
||||||
|
|
||||||
|
describe("<RoomNotifications />", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
stubClient();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render", () => {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const { asFragment } = render(
|
||||||
|
<MatrixClientContext.Provider value={cli}>
|
||||||
|
<DevtoolsContext.Provider
|
||||||
|
value={{
|
||||||
|
room: new Room("!roomId", cli, "@alice:example.com", {
|
||||||
|
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RoomNotifications onBack={() => {}} setTool={() => {}} />
|
||||||
|
</DevtoolsContext.Provider>
|
||||||
|
</MatrixClientContext.Provider>,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<RoomNotifications /> should render 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div
|
||||||
|
class="mx_DevTools_content"
|
||||||
|
>
|
||||||
|
<section>
|
||||||
|
<h2>
|
||||||
|
Room status
|
||||||
|
</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Room unread status:
|
||||||
|
<strong>
|
||||||
|
None
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Notification state is
|
||||||
|
<strong />
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Room is
|
||||||
|
<strong>
|
||||||
|
not encrypted 🚨
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>
|
||||||
|
Main timeline
|
||||||
|
</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Total: 0
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Highlight: 0
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Dot: false
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>
|
||||||
|
Threads timeline
|
||||||
|
</h2>
|
||||||
|
<ul />
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_Dialog_buttons"
|
||||||
|
>
|
||||||
|
<button>
|
||||||
|
Back
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
31
test/stores/notifications/NotificationColor-test.ts
Normal file
31
test/stores/notifications/NotificationColor-test.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { humanReadableNotificationColor, NotificationColor } from "../../../src/stores/notifications/NotificationColor";
|
||||||
|
|
||||||
|
describe("NotificationColor", () => {
|
||||||
|
describe("humanReadableNotificationColor", () => {
|
||||||
|
it.each([
|
||||||
|
[NotificationColor.None, "None"],
|
||||||
|
[NotificationColor.Bold, "Bold"],
|
||||||
|
[NotificationColor.Grey, "Grey"],
|
||||||
|
[NotificationColor.Red, "Red"],
|
||||||
|
[NotificationColor.Unsent, "Unsent"],
|
||||||
|
])("correctly maps the output", (color, output) => {
|
||||||
|
expect(humanReadableNotificationColor(color)).toBe(output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue