mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-15 18:49:21 +00:00
Merge branch 'livekit' into toger5/test-with-new-membershipmanager
This commit is contained in:
17
.github/workflows/blocked.yaml
vendored
Normal file
17
.github/workflows/blocked.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
name: Prevent blocked
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, labeled, unlabeled]
|
||||||
|
jobs:
|
||||||
|
prevent-blocked:
|
||||||
|
name: Prevent blocked
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: read
|
||||||
|
steps:
|
||||||
|
- name: Add notice
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
if: contains(github.event.pull_request.labels.*.name, 'X-Blocked')
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed("PR has been labeled with X-Blocked; it cannot be merged.");
|
||||||
@@ -8,26 +8,26 @@
|
|||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
|
||||||
/>
|
/>
|
||||||
<title><%- title %></title>
|
<title><%- brand %></title>
|
||||||
<script>
|
<script>
|
||||||
window.global = window;
|
window.global = window;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Open graph meta tags -->
|
<!-- Open graph meta tags -->
|
||||||
|
|
||||||
<meta property="og:title" content="<%- title %>" />
|
<meta property="og:title" content="<%- brand %>" />
|
||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content="You're invited to join a call on Element Call"
|
content="You're invited to join a call on <%- brand %>"
|
||||||
/>
|
/>
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:image" content="favicon.png" />
|
<meta property="og:image" content="favicon.png" />
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content="<%- title %>" />
|
<meta name="twitter:title" content="<%- brand %>" />
|
||||||
<meta
|
<meta
|
||||||
name="twitter:description"
|
name="twitter:description"
|
||||||
content="You're invited to join a call on Element Call"
|
content="You're invited to join a call on <%- brand %>"
|
||||||
/>
|
/>
|
||||||
<meta name="twitter:image" content="favicon.png" />
|
<meta name="twitter:image" content="favicon.png" />
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ describe("UrlParams", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("returnToLobby", () => {
|
describe("returnToLobby", () => {
|
||||||
it("is true in SPA mode", () => {
|
it("is false in SPA mode", () => {
|
||||||
expect(getUrlParams("?returnToLobby=false").returnToLobby).toBe(true);
|
expect(getUrlParams("?returnToLobby=true").returnToLobby).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("defaults to false in widget mode", () => {
|
it("defaults to false in widget mode", () => {
|
||||||
|
|||||||
@@ -264,7 +264,9 @@ export const getUrlParams = (
|
|||||||
"skipLobby",
|
"skipLobby",
|
||||||
isWidget && intent === UserIntent.StartNewCall,
|
isWidget && intent === UserIntent.StartNewCall,
|
||||||
),
|
),
|
||||||
returnToLobby: isWidget ? parser.getFlagParam("returnToLobby") : true,
|
// In SPA mode the user should always exit to the home screen when hanging
|
||||||
|
// up, rather than being sent back to the lobby
|
||||||
|
returnToLobby: isWidget ? parser.getFlagParam("returnToLobby") : false,
|
||||||
theme: parser.getParam("theme"),
|
theme: parser.getParam("theme"),
|
||||||
viaServers: !isWidget ? parser.getParam("viaServers") : null,
|
viaServers: !isWidget ? parser.getParam("viaServers") : null,
|
||||||
homeserver: !isWidget ? parser.getParam("homeserver") : null,
|
homeserver: !isWidget ? parser.getParam("homeserver") : null,
|
||||||
|
|||||||
@@ -539,9 +539,7 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
}
|
}
|
||||||
} else if (left && widget !== null) {
|
} else if (left && widget !== null) {
|
||||||
// Left in widget mode:
|
// Left in widget mode:
|
||||||
if (!returnToLobby) {
|
body = returnToLobby ? lobbyView : null;
|
||||||
body = null;
|
|
||||||
}
|
|
||||||
} else if (preload || skipLobby) {
|
} else if (preload || skipLobby) {
|
||||||
body = null;
|
body = null;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
import { expect, test, vi } from "vitest";
|
import { expect, onTestFinished, test, vi } from "vitest";
|
||||||
import { AutoDiscovery } from "matrix-js-sdk/src/autodiscovery";
|
import { AutoDiscovery } from "matrix-js-sdk/src/autodiscovery";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
|
||||||
@@ -15,11 +15,17 @@ import { mockConfig } from "./utils/test";
|
|||||||
import { ElementWidgetActions, widget } from "./widget";
|
import { ElementWidgetActions, widget } from "./widget";
|
||||||
import { ErrorCode } from "./utils/errors.ts";
|
import { ErrorCode } from "./utils/errors.ts";
|
||||||
|
|
||||||
|
const getUrlParams = vi.hoisted(() => vi.fn(() => ({})));
|
||||||
|
vi.mock("./UrlParams", () => ({ getUrlParams }));
|
||||||
|
|
||||||
const actualWidget = await vi.hoisted(async () => vi.importActual("./widget"));
|
const actualWidget = await vi.hoisted(async () => vi.importActual("./widget"));
|
||||||
vi.mock("./widget", () => ({
|
vi.mock("./widget", () => ({
|
||||||
...actualWidget,
|
...actualWidget,
|
||||||
widget: {
|
widget: {
|
||||||
api: { transport: { send: vi.fn(), reply: vi.fn(), stop: vi.fn() } },
|
api: {
|
||||||
|
setAlwaysOnScreen: (): void => {},
|
||||||
|
transport: { send: vi.fn(), reply: vi.fn(), stop: vi.fn() },
|
||||||
|
},
|
||||||
lazyActions: new EventEmitter(),
|
lazyActions: new EventEmitter(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@@ -110,34 +116,45 @@ test("It joins the correct Session", async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("leaveRTCSession closes the widget on a normal hangup", async () => {
|
async function testLeaveRTCSession(
|
||||||
|
cause: "user" | "error",
|
||||||
|
expectClose: boolean,
|
||||||
|
): Promise<void> {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
const session = { leaveRoomSession: vi.fn() } as unknown as MatrixRTCSession;
|
const session = { leaveRoomSession: vi.fn() } as unknown as MatrixRTCSession;
|
||||||
await leaveRTCSession(session, "user");
|
await leaveRTCSession(session, cause);
|
||||||
expect(session.leaveRoomSession).toHaveBeenCalled();
|
expect(session.leaveRoomSession).toHaveBeenCalled();
|
||||||
expect(widget!.api.transport.send).toHaveBeenCalledWith(
|
expect(widget!.api.transport.send).toHaveBeenCalledWith(
|
||||||
ElementWidgetActions.HangupCall,
|
ElementWidgetActions.HangupCall,
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
);
|
);
|
||||||
expect(widget!.api.transport.send).toHaveBeenCalledWith(
|
if (expectClose) {
|
||||||
ElementWidgetActions.Close,
|
expect(widget!.api.transport.send).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
ElementWidgetActions.Close,
|
||||||
);
|
expect.anything(),
|
||||||
|
);
|
||||||
|
expect(widget!.api.transport.stop).toHaveBeenCalled();
|
||||||
|
} else {
|
||||||
|
expect(widget!.api.transport.send).not.toHaveBeenCalledWith(
|
||||||
|
ElementWidgetActions.Close,
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
|
expect(widget!.api.transport.stop).not.toHaveBeenCalled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test("leaveRTCSession closes the widget on a normal hangup", async () => {
|
||||||
|
await testLeaveRTCSession("user", true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("leaveRTCSession doesn't close the widget on a fatal error", async () => {
|
test("leaveRTCSession doesn't close the widget on a fatal error", async () => {
|
||||||
vi.clearAllMocks();
|
await testLeaveRTCSession("error", false);
|
||||||
const session = { leaveRoomSession: vi.fn() } as unknown as MatrixRTCSession;
|
});
|
||||||
await leaveRTCSession(session, "error");
|
|
||||||
expect(session.leaveRoomSession).toHaveBeenCalled();
|
test("leaveRTCSession doesn't close the widget when returning to lobby", async () => {
|
||||||
expect(widget!.api.transport.send).toHaveBeenCalledWith(
|
getUrlParams.mockReturnValue({ returnToLobby: true });
|
||||||
ElementWidgetActions.HangupCall,
|
onTestFinished(() => void getUrlParams.mockReset());
|
||||||
expect.anything(),
|
await testLeaveRTCSession("user", false);
|
||||||
);
|
|
||||||
expect(widget!.api.transport.send).not.toHaveBeenCalledWith(
|
|
||||||
ElementWidgetActions.Close,
|
|
||||||
expect.anything(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("It fails with configuration error if no live kit url config is set in fallback", async () => {
|
test("It fails with configuration error if no live kit url config is set in fallback", async () => {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { PosthogAnalytics } from "./analytics/PosthogAnalytics";
|
|||||||
import { Config } from "./config/Config";
|
import { Config } from "./config/Config";
|
||||||
import { ElementWidgetActions, widget, type WidgetHelpers } from "./widget";
|
import { ElementWidgetActions, widget, type WidgetHelpers } from "./widget";
|
||||||
import { MatrixRTCFocusMissingError } from "./utils/errors.ts";
|
import { MatrixRTCFocusMissingError } from "./utils/errors.ts";
|
||||||
|
import { getUrlParams } from "./UrlParams.ts";
|
||||||
|
|
||||||
const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci";
|
const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci";
|
||||||
|
|
||||||
@@ -126,6 +127,13 @@ export async function enterRTCSession(
|
|||||||
makeKeyDelay: matrixRtcSessionConfig?.key_rotation_on_leave_delay,
|
makeKeyDelay: matrixRtcSessionConfig?.key_rotation_on_leave_delay,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if (widget) {
|
||||||
|
try {
|
||||||
|
await widget.api.transport.send(ElementWidgetActions.JoinCall, {});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error("Failed to send join action", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgetPostHangupProcedure = async (
|
const widgetPostHangupProcedure = async (
|
||||||
@@ -151,7 +159,7 @@ const widgetPostHangupProcedure = async (
|
|||||||
}
|
}
|
||||||
// On a normal user hangup we can shut down and close the widget. But if an
|
// On a normal user hangup we can shut down and close the widget. But if an
|
||||||
// error occurs we should keep the widget open until the user reads it.
|
// error occurs we should keep the widget open until the user reads it.
|
||||||
if (cause === "user") {
|
if (cause === "user" && !getUrlParams().returnToLobby) {
|
||||||
try {
|
try {
|
||||||
await widget.api.transport.send(ElementWidgetActions.Close, {});
|
await widget.api.transport.send(ElementWidgetActions.Close, {});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -496,6 +496,10 @@ export class CallViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
return displaynameMap;
|
return displaynameMap;
|
||||||
}),
|
}),
|
||||||
|
// It turns out that doing the disambiguation above is rather expensive on Safari (10x slower
|
||||||
|
// than on Chrome/Firefox). This means it is important that we share() the result so that we
|
||||||
|
// don't do this work more times than we need to. This is achieve through the state() operator:
|
||||||
|
this.scope.state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
}),
|
}),
|
||||||
htmlTemplate.default({
|
htmlTemplate.default({
|
||||||
data: {
|
data: {
|
||||||
title: env.VITE_PRODUCT_NAME || "Element Call",
|
brand: env.VITE_PRODUCT_NAME || "Element Call",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user