feat: show call participants in room list (Discord-style)
Docker / Docker Buildx (push) Has been cancelled
Build Debian package / Build package (release) Has been cancelled
Build and Deploy / prepare (release) Has been cancelled
Deploy release / Deploy to Cloudflare Pages (release) Has been cancelled
Build and Deploy / Trigger Pro pipeline (release) Has been cancelled
Build and Deploy / Windows arm64 (release) Has been cancelled
Build and Deploy / Windows x64 (release) Has been cancelled
Build and Deploy / macOS (release) Has been cancelled
Build and Deploy / Linux amd64 (sqlcipher static) (release) Has been cancelled
Build and Deploy / Linux arm64 (sqlcipher static) (release) Has been cancelled
Build and Deploy / ${{ needs.prepare.outputs.deploy == 'true' && 'Deploy' || 'Deploy (dry-run)' }} (release) Has been cancelled
Build and Deploy / Deploy builds to ESS (release) Has been cancelled

This commit is contained in:
sorB
2026-05-10 14:25:35 +02:00
parent b797925316
commit 3da363517f
4610 changed files with 827237 additions and 1 deletions
@@ -0,0 +1,32 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`link-tooltip does nothing for empty element 1`] = `
<DocumentFragment>
<div />
</DocumentFragment>
`;
exports[`link-tooltip wraps single anchor 1`] = `
<DocumentFragment>
<div>
<span
aria-labelledby="_r_0_"
tabindex="0"
>
<a
href="/foo"
>
click
</a>
</span>
</div>
</DocumentFragment>
`;
@@ -0,0 +1,103 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`keyword pills should do nothing for empty element 1`] = `
<DocumentFragment>
<div />
</DocumentFragment>
`;
exports[`keyword pills should pillify 1`] = `
<DocumentFragment>
<div>
Foo
<bdi>
<span
tabindex="0"
>
<span
class="mx_Pill mx_KeywordPill"
>
<span
class="mx_Pill_text"
>
TeST
</span>
</span>
</span>
</bdi>
Bar
</div>
</DocumentFragment>
`;
exports[`mention pills should do nothing for empty element 1`] = `
<DocumentFragment>
<div />
</DocumentFragment>
`;
exports[`mention pills should pillify @room 1`] = `
<DocumentFragment>
<div>
<bdi>
<span
tabindex="0"
>
<span
class="mx_Pill mx_AtRoomPill"
>
<span
aria-hidden="true"
class="_avatar_va14e_8 mx_BaseAvatar _avatar-imageless_va14e_55"
data-color="4"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 16px;"
>
!
</span>
<span
class="mx_Pill_text"
>
@room
</span>
</span>
</span>
</bdi>
</div>
</DocumentFragment>
`;
exports[`mention pills should pillify @room in an intentional mentions world 1`] = `
<DocumentFragment>
<div>
<bdi>
<span
tabindex="0"
>
<span
class="mx_Pill mx_AtRoomPill"
>
<span
aria-hidden="true"
class="_avatar_va14e_8 mx_BaseAvatar _avatar-imageless_va14e_55"
data-color="4"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 16px;"
>
!
</span>
<span
class="mx_Pill_text"
>
@room
</span>
</span>
</span>
</bdi>
</div>
</DocumentFragment>
`;
@@ -0,0 +1,47 @@
/*
Copyright 2024-2025 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { screen, fireEvent, render, type RenderResult } from "jest-matrix-react";
import parse from "html-react-parser";
import { ambiguousLinkTooltipRenderer, combineRenderers } from "../../../src/renderer";
import PlatformPeg from "../../../src/PlatformPeg";
import type BasePlatform from "../../../src/BasePlatform";
describe("link-tooltip", () => {
jest.spyOn(PlatformPeg, "get").mockReturnValue({ needsUrlTooltips: () => true } as unknown as BasePlatform);
function renderTooltips(input: string): RenderResult {
return render(
<>
{parse(input, {
replace: combineRenderers(ambiguousLinkTooltipRenderer)({ isHtml: true }),
})}
</>,
);
}
it("does nothing for empty element", () => {
const { asFragment } = renderTooltips("<div></div>");
expect(asFragment()).toMatchSnapshot();
});
it("wraps single anchor", () => {
const { container, asFragment } = renderTooltips(`
<div>
<a href="/foo">click</a>
</div>
`);
expect(asFragment()).toMatchSnapshot();
const anchor = container.querySelector("a")!;
expect(anchor.getAttribute("href")).toEqual("/foo");
fireEvent.focus(anchor.parentElement!);
expect(screen.getByLabelText("http://localhost/foo")).toBe(anchor.parentElement!);
});
});
@@ -0,0 +1,228 @@
/*
Copyright 2024-2025 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { render, type RenderResult } from "jest-matrix-react";
import {
MatrixEvent,
ConditionKind,
EventType,
PushRuleActionName,
Room,
TweakName,
type MatrixClient,
} from "matrix-js-sdk/src/matrix";
import { mocked } from "jest-mock";
import parse from "html-react-parser";
import { PushProcessor } from "matrix-js-sdk/src/pushprocessor";
import { keywordPillRenderer, mentionPillRenderer, combineRenderers } from "../../../src/renderer";
import { stubClient, withClientContextRenderOptions } from "../../test-utils";
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
import DMRoomMap from "../../../src/utils/DMRoomMap";
describe("mention pills", () => {
let cli: MatrixClient;
let room: Room;
const roomId = "!room:id";
const event = new MatrixEvent({
room_id: roomId,
type: EventType.RoomMessage,
content: {
body: "@room",
},
});
beforeEach(() => {
stubClient();
cli = MatrixClientPeg.safeGet();
// @ts-expect-error
cli.pushProcessor = new PushProcessor(cli);
room = new Room(roomId, cli, cli.getUserId()!);
room.currentState.mayTriggerNotifOfType = jest.fn().mockReturnValue(true);
(cli.getRoom as jest.Mock).mockReturnValue(room);
cli.pushRules!.global = {
override: [
{
rule_id: ".m.rule.roomnotif",
default: true,
enabled: true,
conditions: [
{
kind: ConditionKind.EventMatch,
key: "content.body",
pattern: "@room",
},
],
actions: [
PushRuleActionName.Notify,
{
set_tweak: TweakName.Highlight,
value: true,
},
],
},
{
rule_id: ".m.rule.is_room_mention",
default: true,
enabled: true,
conditions: [
{
kind: ConditionKind.EventPropertyIs,
key: "content.m\\.mentions.room",
value: true,
},
{
kind: ConditionKind.SenderNotificationPermission,
key: "room",
},
],
actions: [
PushRuleActionName.Notify,
{
set_tweak: TweakName.Highlight,
},
],
},
],
};
DMRoomMap.makeShared(cli);
});
function renderPills(input: string, mxEvent?: MatrixEvent): RenderResult {
return render(
<>
{parse(input, {
replace: combineRenderers(mentionPillRenderer)({
mxEvent: mxEvent ?? event,
room,
isHtml: true,
}),
})}
</>,
withClientContextRenderOptions(cli),
);
}
it("should do nothing for empty element", () => {
const input = "<div></div>";
const { asFragment } = renderPills(input);
expect(asFragment()).toMatchSnapshot();
});
it("should pillify @room", () => {
const input = "<div>@room</div>";
const { container, asFragment } = renderPills(input);
expect(asFragment()).toMatchSnapshot();
expect(container.querySelector(".mx_Pill.mx_AtRoomPill")?.textContent).toBe("!@room");
});
it("should pillify @room in an intentional mentions world", () => {
mocked(MatrixClientPeg.safeGet().supportsIntentionalMentions).mockReturnValue(true);
const { container, asFragment } = renderPills(
"<div>@room</div>",
new MatrixEvent({
room_id: roomId,
type: EventType.RoomMessage,
content: {
"body": "@room",
"m.mentions": {
room: true,
},
},
}),
);
expect(asFragment()).toMatchSnapshot();
expect(container.querySelector(".mx_Pill.mx_AtRoomPill")?.textContent).toBe("!@room");
});
});
describe("keyword pills", () => {
let cli: MatrixClient;
const keywordRegexpPattern = /(test)/i;
beforeEach(() => {
stubClient();
cli = MatrixClientPeg.safeGet();
cli.pushRules!.global = {
override: [
{
rule_id: ".m.rule.roomnotif",
default: true,
enabled: true,
conditions: [
{
kind: ConditionKind.EventMatch,
key: "content.body",
pattern: "@room",
},
],
actions: [
PushRuleActionName.Notify,
{
set_tweak: TweakName.Highlight,
value: true,
},
],
},
{
rule_id: ".m.rule.is_room_mention",
default: true,
enabled: true,
conditions: [
{
kind: ConditionKind.EventPropertyIs,
key: "content.m\\.mentions.room",
value: true,
},
{
kind: ConditionKind.SenderNotificationPermission,
key: "room",
},
],
actions: [
PushRuleActionName.Notify,
{
set_tweak: TweakName.Highlight,
},
],
},
],
};
DMRoomMap.makeShared(cli);
});
function renderPills(input: string): RenderResult {
return render(
<>
{parse(input, {
replace: combineRenderers(keywordPillRenderer)({
isHtml: true,
keywordRegexpPattern,
}),
})}
</>,
withClientContextRenderOptions(cli),
);
}
it("should do nothing for empty element", () => {
const input = "<div></div>";
const { asFragment } = renderPills(input);
expect(asFragment()).toMatchSnapshot();
});
it("should pillify", () => {
const input = "<div>Foo TeST Bar</div>";
const { container, asFragment } = renderPills(input);
expect(asFragment()).toMatchSnapshot();
expect(container.querySelector(".mx_Pill.mx_KeywordPill")?.textContent).toBe("TeST");
});
});