Skip to content

Commit

Permalink
Introduce intent URL param and make it change the default lobby beh…
Browse files Browse the repository at this point in the history
…aviour
  • Loading branch information
hughns committed Nov 22, 2024
1 parent b8e36fc commit 728ef24
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 4 deletions.
3 changes: 2 additions & 1 deletion docs/url-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ There are two formats for Element Call urls.
| `hideHeader` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the room header when in a call. |
| `hideScreensharing` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. |
| `homeserver` | | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. |
| `intent` | `start_call` or `join_existing` | No, defaults to `start_call` | No, defaults to `start_call` | The intent of the user with respect to the call. e.g. if they clicked a Start Call button, this would be `start_call`. If it was a Join Call button, it would be `join_existing`. |
| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code | No | No | The language the app should use. |
| `parentUrl` | | Yes | Not applicable | The url used to send widget action postMessages. This should be the domain of the client or the webview the widget is hosted in. (in case the widget is not in an Iframe but in a dedicated webview we send the postMessages same WebView the widget lives in. Filtering is done in the widget so it ignores the messages it receives from itself) |
| `password` | | No | No | E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) |
Expand All @@ -56,7 +57,7 @@ There are two formats for Element Call urls.
| `returnToLobby` | `true` or `false` | No, defaults to `false` | Not applicable | Displays the lobby in widget mode after leaving a call; shows a blank page if set to `false`. Useful for video rooms. |
| `roomId` | [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. |
| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. |
| `skipLobby` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. |
| `skipLobby` | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. |
| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. |
| `userId` | [Matrix User Identifier](https://spec.matrix.org/v1.12/appendices/#user-identifiers) | Yes | Not applicable | The Matrix user ID. |
| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. |
Expand Down
42 changes: 41 additions & 1 deletion src/UrlParams.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ Please see LICENSE in the repository root for full details.

import { describe, expect, it } from "vitest";

import { getRoomIdentifierFromUrl } from "../src/UrlParams";
import {
getRoomIdentifierFromUrl,
getUrlParams,
UserIntent,
} from "../src/UrlParams";

const ROOM_NAME = "roomNameHere";
const ROOM_ID = "!d45f138fsd";
Expand Down Expand Up @@ -86,4 +90,40 @@ describe("UrlParams", () => {
.roomAlias,
).toBeFalsy();
});

describe("intent", () => {
it("defaults to start_call", () => {
expect(getUrlParams().intent).toBe(UserIntent.StartNewCall);
});

it("ignores intent if it is not a valid value", () => {
expect(getUrlParams("?intent=foo").intent).toBe(UserIntent.StartNewCall);
});

it("accepts join_existing", () => {
expect(getUrlParams("?intent=join_existing").intent).toBe(
UserIntent.JoinExistingCall,
);
});
});

describe("skipLobby", () => {
it("defaults to false", () => {
expect(getUrlParams().skipLobby).toBe(false);
});

it("defaults to false if intent is start_call in SPA mode", () => {
expect(getUrlParams("?intent=start_call").skipLobby).toBe(false);
});

it("defaults to true if intent is start_call in widget mode", () => {
expect(getUrlParams("?intent=start_call&widgetId=12345").skipLobby).toBe(
true,
);
});

it("default to false if intent is join_existing", () => {
expect(getUrlParams("?intent=join_existing").skipLobby).toBe(false);
});
});
});
28 changes: 26 additions & 2 deletions src/UrlParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ interface RoomIdentifier {
viaServers: string[];
}

export enum UserIntent {
StartNewCall = "start_call",
JoinExistingCall = "join_existing",
}

// If you need to add a new flag to this interface, prefer a name that describes
// a specific behavior (such as 'confineToRoom'), rather than one that describes
// the situations that call for this behavior ('isEmbedded'). This makes it
Expand Down Expand Up @@ -142,6 +147,13 @@ export interface UrlParams {
* creating a spa link.
*/
homeserver: string | null;

/**
* The user's intent with respect to the call.
* e.g. if they clicked a Start Call button, this would be `start_call`.
* If it was a Join Call button, it would be `join_existing`.
*/
intent: string | null;
}

// This is here as a stopgap, but what would be far nicer is a function that
Expand Down Expand Up @@ -211,8 +223,16 @@ export const getUrlParams = (

const fontScale = parseFloat(parser.getParam("fontScale") ?? "");

let intent = parser.getParam("intent");
if (!Object.values(UserIntent).includes(intent as UserIntent)) {
intent = UserIntent.StartNewCall;
}
const widgetId = parser.getParam("widgetId");

const isWidget = !!widgetId;

return {
widgetId: parser.getParam("widgetId"),
widgetId,
parentUrl: parser.getParam("parentUrl"),

// NB. we don't validate roomId here as we do in getRoomIdentifierFromUrl:
Expand All @@ -239,11 +259,15 @@ export const getUrlParams = (
analyticsID: parser.getParam("analyticsID"),
allowIceFallback: parser.getFlagParam("allowIceFallback"),
perParticipantE2EE: parser.getFlagParam("perParticipantE2EE"),
skipLobby: parser.getFlagParam("skipLobby"),
skipLobby: parser.getFlagParam(
"skipLobby",
isWidget && intent === UserIntent.StartNewCall,
),
returnToLobby: parser.getFlagParam("returnToLobby"),
theme: parser.getParam("theme"),
viaServers: parser.getParam("viaServers"),
homeserver: parser.getParam("homeserver"),
intent,
};
};

Expand Down

0 comments on commit 728ef24

Please sign in to comment.