Merge pull request #1177 from vector-im/SimonBrandner/feat/friendly-url
This commit is contained in:
@@ -106,6 +106,7 @@
|
|||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^29.2.2",
|
"jest": "^29.2.2",
|
||||||
"jest-environment-jsdom": "^29.3.1",
|
"jest-environment-jsdom": "^29.3.1",
|
||||||
|
"jest-mock": "^29.5.0",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"sass": "^1.42.1",
|
"sass": "^1.42.1",
|
||||||
"storybook-builder-vite": "^0.1.12",
|
"storybook-builder-vite": "^0.1.12",
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { HomePage } from "./home/HomePage";
|
|||||||
import { LoginPage } from "./auth/LoginPage";
|
import { LoginPage } from "./auth/LoginPage";
|
||||||
import { RegisterPage } from "./auth/RegisterPage";
|
import { RegisterPage } from "./auth/RegisterPage";
|
||||||
import { RoomPage } from "./room/RoomPage";
|
import { RoomPage } from "./room/RoomPage";
|
||||||
import { RoomRedirect } from "./room/RoomRedirect";
|
|
||||||
import { ClientProvider } from "./ClientContext";
|
import { ClientProvider } from "./ClientContext";
|
||||||
import { usePageFocusStyle } from "./usePageFocusStyle";
|
import { usePageFocusStyle } from "./usePageFocusStyle";
|
||||||
import { SequenceDiagramViewerPage } from "./SequenceDiagramViewerPage";
|
import { SequenceDiagramViewerPage } from "./SequenceDiagramViewerPage";
|
||||||
@@ -71,14 +70,11 @@ export default function App({ history }: AppProps) {
|
|||||||
<SentryRoute exact path="/register">
|
<SentryRoute exact path="/register">
|
||||||
<RegisterPage />
|
<RegisterPage />
|
||||||
</SentryRoute>
|
</SentryRoute>
|
||||||
<SentryRoute path="/room/:roomId?">
|
|
||||||
<RoomPage />
|
|
||||||
</SentryRoute>
|
|
||||||
<SentryRoute path="/inspector">
|
<SentryRoute path="/inspector">
|
||||||
<SequenceDiagramViewerPage />
|
<SequenceDiagramViewerPage />
|
||||||
</SentryRoute>
|
</SentryRoute>
|
||||||
<SentryRoute path="*">
|
<SentryRoute path="*">
|
||||||
<RoomRedirect />
|
<RoomPage />
|
||||||
</SentryRoute>
|
</SentryRoute>
|
||||||
</Switch>
|
</Switch>
|
||||||
</OverlayProvider>
|
</OverlayProvider>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2022 New Vector Ltd
|
Copyright 2022 - 2023 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
import { Config } from "./config/Config";
|
||||||
|
|
||||||
interface UrlParams {
|
interface UrlParams {
|
||||||
roomAlias: string | null;
|
roomAlias: string | null;
|
||||||
roomId: string | null;
|
roomId: string | null;
|
||||||
@@ -93,14 +95,39 @@ interface UrlParams {
|
|||||||
* @returns The app parameters encoded in the URL
|
* @returns The app parameters encoded in the URL
|
||||||
*/
|
*/
|
||||||
export const getUrlParams = (
|
export const getUrlParams = (
|
||||||
query: string = window.location.search,
|
ignoreRoomAlias?: boolean,
|
||||||
fragment: string = window.location.hash
|
search = window.location.search,
|
||||||
|
pathname = window.location.pathname,
|
||||||
|
hash = window.location.hash
|
||||||
): UrlParams => {
|
): UrlParams => {
|
||||||
const fragmentQueryStart = fragment.indexOf("?");
|
let roomAlias: string | undefined;
|
||||||
|
if (!ignoreRoomAlias) {
|
||||||
|
if (hash === "") {
|
||||||
|
roomAlias = pathname.substring(1); // Strip the "/"
|
||||||
|
|
||||||
|
// Delete "/room/" and "?", if present
|
||||||
|
if (roomAlias.startsWith("room/")) {
|
||||||
|
roomAlias = roomAlias.substring("room/".length);
|
||||||
|
}
|
||||||
|
// Add "#", if not present
|
||||||
|
if (!roomAlias.startsWith("#")) {
|
||||||
|
roomAlias = `#${roomAlias}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
roomAlias = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add server part, if not present
|
||||||
|
if (!roomAlias.includes(":")) {
|
||||||
|
roomAlias = `${roomAlias}:${Config.defaultServerName()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fragmentQueryStart = hash.indexOf("?");
|
||||||
const fragmentParams = new URLSearchParams(
|
const fragmentParams = new URLSearchParams(
|
||||||
fragmentQueryStart === -1 ? "" : fragment.substring(fragmentQueryStart)
|
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart)
|
||||||
);
|
);
|
||||||
const queryParams = new URLSearchParams(query);
|
const queryParams = new URLSearchParams(search);
|
||||||
|
|
||||||
// Normally, URL params should be encoded in the fragment so as to avoid
|
// Normally, URL params should be encoded in the fragment so as to avoid
|
||||||
// leaking them to the server. However, we also check the normal query
|
// leaking them to the server. However, we also check the normal query
|
||||||
@@ -114,16 +141,10 @@ export const getUrlParams = (
|
|||||||
...queryParams.getAll(name),
|
...queryParams.getAll(name),
|
||||||
];
|
];
|
||||||
|
|
||||||
// The part of the fragment before the ?
|
|
||||||
const fragmentRoute =
|
|
||||||
fragmentQueryStart === -1
|
|
||||||
? fragment
|
|
||||||
: fragment.substring(0, fragmentQueryStart);
|
|
||||||
|
|
||||||
const fontScale = parseFloat(getParam("fontScale") ?? "");
|
const fontScale = parseFloat(getParam("fontScale") ?? "");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
roomAlias: fragmentRoute.length > 1 ? fragmentRoute : null,
|
roomAlias: !roomAlias || roomAlias.includes("!") ? null : roomAlias,
|
||||||
roomId: getParam("roomId"),
|
roomId: getParam("roomId"),
|
||||||
viaServers: getAllParams("via"),
|
viaServers: getAllParams("via"),
|
||||||
isEmbedded: hasParam("embed"),
|
isEmbedded: hasParam("embed"),
|
||||||
@@ -149,6 +170,9 @@ export const getUrlParams = (
|
|||||||
* @returns The app parameters for the current URL
|
* @returns The app parameters for the current URL
|
||||||
*/
|
*/
|
||||||
export const useUrlParams = (): UrlParams => {
|
export const useUrlParams = (): UrlParams => {
|
||||||
const { hash, search } = useLocation();
|
const { search, pathname, hash } = useLocation();
|
||||||
return useMemo(() => getUrlParams(search, hash), [search, hash]);
|
return useMemo(
|
||||||
|
() => getUrlParams(false, search, pathname, hash),
|
||||||
|
[search, pathname, hash]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ export function CallList({ rooms, client, disableFacepile }: CallListProps) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.callList}>
|
<div className={styles.callList}>
|
||||||
{rooms.map(({ roomId, roomName, avatarUrl, participants }) => (
|
{rooms.map(({ roomAlias, roomName, avatarUrl, participants }) => (
|
||||||
<CallTile
|
<CallTile
|
||||||
key={roomId}
|
key={roomAlias}
|
||||||
client={client}
|
client={client}
|
||||||
name={roomName}
|
name={roomName}
|
||||||
avatarUrl={avatarUrl}
|
avatarUrl={avatarUrl}
|
||||||
roomId={roomId}
|
roomAlias={roomAlias}
|
||||||
participants={participants}
|
participants={participants}
|
||||||
disableFacepile={disableFacepile}
|
disableFacepile={disableFacepile}
|
||||||
/>
|
/>
|
||||||
@@ -59,7 +59,7 @@ export function CallList({ rooms, client, disableFacepile }: CallListProps) {
|
|||||||
interface CallTileProps {
|
interface CallTileProps {
|
||||||
name: string;
|
name: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
roomId: string;
|
roomAlias: string;
|
||||||
participants: RoomMember[];
|
participants: RoomMember[];
|
||||||
client: MatrixClient;
|
client: MatrixClient;
|
||||||
disableFacepile?: boolean;
|
disableFacepile?: boolean;
|
||||||
@@ -67,14 +67,17 @@ interface CallTileProps {
|
|||||||
function CallTile({
|
function CallTile({
|
||||||
name,
|
name,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
roomId,
|
roomAlias,
|
||||||
participants,
|
participants,
|
||||||
client,
|
client,
|
||||||
disableFacepile,
|
disableFacepile,
|
||||||
}: CallTileProps) {
|
}: CallTileProps) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.callTile}>
|
<div className={styles.callTile}>
|
||||||
<Link to={`/room/${roomId}`} className={styles.callTileLink}>
|
<Link
|
||||||
|
to={`/${roomAlias.substring(1).split(":")[0]}`}
|
||||||
|
className={styles.callTileLink}
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
size={Size.LG}
|
size={Size.LG}
|
||||||
bgKey={name}
|
bgKey={name}
|
||||||
@@ -86,7 +89,7 @@ function CallTile({
|
|||||||
<Body overflowEllipsis fontWeight="semiBold">
|
<Body overflowEllipsis fontWeight="semiBold">
|
||||||
{name}
|
{name}
|
||||||
</Body>
|
</Body>
|
||||||
<Caption overflowEllipsis>{getRoomUrl(roomId)}</Caption>
|
<Caption overflowEllipsis>{getRoomUrl(roomAlias)}</Caption>
|
||||||
{participants && !disableFacepile && (
|
{participants && !disableFacepile && (
|
||||||
<Facepile
|
<Facepile
|
||||||
className={styles.facePile}
|
className={styles.facePile}
|
||||||
@@ -100,7 +103,7 @@ function CallTile({
|
|||||||
<CopyButton
|
<CopyButton
|
||||||
className={styles.copyButton}
|
className={styles.copyButton}
|
||||||
variant="icon"
|
variant="icon"
|
||||||
value={getRoomUrl(roomId)}
|
value={getRoomUrl(roomAlias)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -71,8 +71,9 @@ export function RegisteredView({ client, isPasswordlessUser }: Props) {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const [roomAlias] = await createRoom(client, roomName, ptt);
|
const [roomAlias] = await createRoom(client, roomName, ptt);
|
||||||
|
|
||||||
if (roomAlias) {
|
if (roomAlias) {
|
||||||
history.push(`/room/${roomAlias}`);
|
history.push(`/${roomAlias.substring(1).split(":")[0]}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,8 +93,7 @@ export const UnauthenticatedView: FC = () => {
|
|||||||
setOnFinished(() => {
|
setOnFinished(() => {
|
||||||
setClient({ client, session });
|
setClient({ client, session });
|
||||||
const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName);
|
const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName);
|
||||||
const [, serverName] = client.getUserId()!.split(":");
|
history.push(`/${aliasLocalpart}`);
|
||||||
history.push(`/room/#${aliasLocalpart}:${serverName}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -111,7 +110,7 @@ export const UnauthenticatedView: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setClient({ client, session });
|
setClient({ client, session });
|
||||||
history.push(`/room/${roomAlias}`);
|
history.push(`/${roomAlias.substring(1).split(":")[0]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
submit().catch((error) => {
|
submit().catch((error) => {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { GroupCallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/groupCallEv
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
export interface GroupCallRoom {
|
export interface GroupCallRoom {
|
||||||
roomId: string;
|
roomAlias: string;
|
||||||
roomName: string;
|
roomName: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -89,12 +89,13 @@ export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] {
|
|||||||
|
|
||||||
const groupCalls = client.groupCallEventHandler.groupCalls.values();
|
const groupCalls = client.groupCallEventHandler.groupCalls.values();
|
||||||
const rooms = Array.from(groupCalls).map((groupCall) => groupCall.room);
|
const rooms = Array.from(groupCalls).map((groupCall) => groupCall.room);
|
||||||
const sortedRooms = sortRooms(client, rooms);
|
const filteredRooms = rooms.filter((r) => r.getCanonicalAlias()); // We don't display rooms without an alias
|
||||||
|
const sortedRooms = sortRooms(client, filteredRooms);
|
||||||
const items = sortedRooms.map((room) => {
|
const items = sortedRooms.map((room) => {
|
||||||
const groupCall = client.getGroupCallForRoom(room.roomId)!;
|
const groupCall = client.getGroupCallForRoom(room.roomId)!;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
roomId: room.getCanonicalAlias() || room.roomId,
|
roomAlias: room.getCanonicalAlias(),
|
||||||
roomName: room.name,
|
roomName: room.name,
|
||||||
avatarUrl: room.getMxcAvatarUrl()!,
|
avatarUrl: room.getMxcAvatarUrl()!,
|
||||||
room,
|
room,
|
||||||
@@ -103,7 +104,7 @@ export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
setRooms(items);
|
setRooms(items as GroupCallRoom[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRooms();
|
updateRooms();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export class Initializer {
|
|||||||
languageDetector.addDetector({
|
languageDetector.addDetector({
|
||||||
name: "urlFragment",
|
name: "urlFragment",
|
||||||
// Look for a language code in the URL's fragment
|
// Look for a language code in the URL's fragment
|
||||||
lookup: () => getUrlParams().lang ?? undefined,
|
lookup: () => getUrlParams(true).lang ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
i18n
|
i18n
|
||||||
@@ -140,7 +140,7 @@ export class Initializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Custom fonts
|
// Custom fonts
|
||||||
const { fonts, fontScale } = getUrlParams();
|
const { fonts, fontScale } = getUrlParams(true);
|
||||||
if (fontScale !== null) {
|
if (fontScale !== null) {
|
||||||
document.documentElement.style.setProperty(
|
document.documentElement.style.setProperty(
|
||||||
"--font-scale",
|
"--font-scale",
|
||||||
|
|||||||
@@ -345,15 +345,11 @@ export async function createRoom(
|
|||||||
// Returns a URL to that will load Element Call with the given room
|
// Returns a URL to that will load Element Call with the given room
|
||||||
export function getRoomUrl(roomIdOrAlias: string): string {
|
export function getRoomUrl(roomIdOrAlias: string): string {
|
||||||
if (roomIdOrAlias.startsWith("#")) {
|
if (roomIdOrAlias.startsWith("#")) {
|
||||||
const [localPart, host] = roomIdOrAlias.replace("#", "").split(":");
|
return `${window.location.protocol}//${window.location.host}/${
|
||||||
|
roomIdOrAlias.substring(1).split(":")[0]
|
||||||
if (host !== Config.defaultServerName()) {
|
}`;
|
||||||
return `${window.location.protocol}//${window.location.host}/room/${roomIdOrAlias}`;
|
|
||||||
} else {
|
|
||||||
return `${window.location.protocol}//${window.location.host}/${localPart}`;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return `${window.location.protocol}//${window.location.host}/room/#?roomId=${roomIdOrAlias}`;
|
return `${window.location.protocol}//${window.location.host}/room?roomId=${roomIdOrAlias}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 New Vector Ltd
|
|
||||||
|
|
||||||
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 { useEffect } from "react";
|
|
||||||
import { useLocation, useHistory } from "react-router-dom";
|
|
||||||
|
|
||||||
import { Config } from "../config/Config";
|
|
||||||
import { LoadingView } from "../FullScreenView";
|
|
||||||
|
|
||||||
// A component that, when loaded, redirects the client to a full room URL
|
|
||||||
// based on the current URL being an abbreviated room URL
|
|
||||||
export function RoomRedirect() {
|
|
||||||
const { pathname } = useLocation();
|
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let roomId = pathname;
|
|
||||||
|
|
||||||
if (pathname.startsWith("/")) {
|
|
||||||
roomId = roomId.substring(1, roomId.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!roomId.startsWith("#") && !roomId.startsWith("!")) {
|
|
||||||
roomId = `#${roomId}:${Config.defaultServerName()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
history.replace(`/room/${roomId.toLowerCase()}`);
|
|
||||||
}, [pathname, history]);
|
|
||||||
|
|
||||||
return <LoadingView />;
|
|
||||||
}
|
|
||||||
98
test/UrlParams-test.ts
Normal file
98
test/UrlParams-test.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 New Vector Ltd
|
||||||
|
|
||||||
|
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 { mocked } from "jest-mock";
|
||||||
|
import { getUrlParams } from "../src/UrlParams";
|
||||||
|
import { Config } from "../src/config/Config";
|
||||||
|
|
||||||
|
const ROOM_NAME = "roomNameHere";
|
||||||
|
const ROOM_ID = "d45f138fsd";
|
||||||
|
const ORIGIN = "https://call.element.io";
|
||||||
|
const HOMESERVER = "call.ems.host";
|
||||||
|
|
||||||
|
jest.mock("../src/config/Config");
|
||||||
|
|
||||||
|
describe("UrlParams", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
mocked(Config.defaultServerName).mockReturnValue("call.ems.host");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("handles URL with /room/", () => {
|
||||||
|
it("and nothing else", () => {
|
||||||
|
expect(getUrlParams(false, "", `/room/${ROOM_NAME}`, "").roomAlias).toBe(
|
||||||
|
`#${ROOM_NAME}:${HOMESERVER}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("and #", () => {
|
||||||
|
expect(
|
||||||
|
getUrlParams(false, "", `${ORIGIN}/room/`, `#${ROOM_NAME}`).roomAlias
|
||||||
|
).toBe(`#${ROOM_NAME}:${HOMESERVER}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("and # and server part", () => {
|
||||||
|
expect(
|
||||||
|
getUrlParams(false, "", `/room/`, `#${ROOM_NAME}:${HOMESERVER}`)
|
||||||
|
.roomAlias
|
||||||
|
).toBe(`#${ROOM_NAME}:${HOMESERVER}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("and server part", () => {
|
||||||
|
expect(
|
||||||
|
getUrlParams(false, "", `/room/${ROOM_NAME}:${HOMESERVER}`, "")
|
||||||
|
.roomAlias
|
||||||
|
).toBe(`#${ROOM_NAME}:${HOMESERVER}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("handles URL without /room/", () => {
|
||||||
|
it("and nothing else", () => {
|
||||||
|
expect(getUrlParams(false, "", `/${ROOM_NAME}`, "").roomAlias).toBe(
|
||||||
|
`#${ROOM_NAME}:${HOMESERVER}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("and with #", () => {
|
||||||
|
expect(getUrlParams(false, "", "", `#${ROOM_NAME}`).roomAlias).toBe(
|
||||||
|
`#${ROOM_NAME}:${HOMESERVER}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("and with # and server part", () => {
|
||||||
|
expect(
|
||||||
|
getUrlParams(false, "", "", `#${ROOM_NAME}:${HOMESERVER}`).roomAlias
|
||||||
|
).toBe(`#${ROOM_NAME}:${HOMESERVER}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("and with server part", () => {
|
||||||
|
expect(
|
||||||
|
getUrlParams(false, "", `/${ROOM_NAME}:${HOMESERVER}`, "").roomAlias
|
||||||
|
).toBe(`#${ROOM_NAME}:${HOMESERVER}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("handles search params", () => {
|
||||||
|
it("(roomId)", () => {
|
||||||
|
expect(getUrlParams(true, `?roomId=${ROOM_ID}`).roomId).toBe(ROOM_ID);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores room alias", () => {
|
||||||
|
expect(
|
||||||
|
getUrlParams(true, "", `/room/${ROOM_NAME}:${HOMESERVER}`).roomAlias
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -34,7 +34,7 @@ describe("CallList", () => {
|
|||||||
|
|
||||||
it("should show room", async () => {
|
it("should show room", async () => {
|
||||||
const rooms = [
|
const rooms = [
|
||||||
{ roomName: "Room #1", roomId: "!roomId" },
|
{ roomName: "Room #1", roomAlias: "#room-name:server.org" },
|
||||||
] as GroupCallRoom[];
|
] as GroupCallRoom[];
|
||||||
|
|
||||||
const result = renderComponent(rooms);
|
const result = renderComponent(rooms);
|
||||||
|
|||||||
45
yarn.lock
45
yarn.lock
@@ -2014,6 +2014,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@sinclair/typebox" "^0.24.1"
|
"@sinclair/typebox" "^0.24.1"
|
||||||
|
|
||||||
|
"@jest/schemas@^29.4.3":
|
||||||
|
version "29.4.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
|
||||||
|
integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==
|
||||||
|
dependencies:
|
||||||
|
"@sinclair/typebox" "^0.25.16"
|
||||||
|
|
||||||
"@jest/source-map@^29.2.0":
|
"@jest/source-map@^29.2.0":
|
||||||
version "29.2.0"
|
version "29.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.2.0.tgz#ab3420c46d42508dcc3dc1c6deee0b613c235744"
|
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.2.0.tgz#ab3420c46d42508dcc3dc1c6deee0b613c235744"
|
||||||
@@ -2088,6 +2095,18 @@
|
|||||||
"@types/yargs" "^17.0.8"
|
"@types/yargs" "^17.0.8"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
|
|
||||||
|
"@jest/types@^29.5.0":
|
||||||
|
version "29.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593"
|
||||||
|
integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==
|
||||||
|
dependencies:
|
||||||
|
"@jest/schemas" "^29.4.3"
|
||||||
|
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||||
|
"@types/istanbul-reports" "^3.0.0"
|
||||||
|
"@types/node" "*"
|
||||||
|
"@types/yargs" "^17.0.8"
|
||||||
|
chalk "^4.0.0"
|
||||||
|
|
||||||
"@joshwooding/vite-plugin-react-docgen-typescript@0.0.2":
|
"@joshwooding/vite-plugin-react-docgen-typescript@0.0.2":
|
||||||
version "0.0.2"
|
version "0.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.0.2.tgz#e0ae8c94f468da3a273a7b0acf23ba3565f86cbc"
|
resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.0.2.tgz#e0ae8c94f468da3a273a7b0acf23ba3565f86cbc"
|
||||||
@@ -3098,6 +3117,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f"
|
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f"
|
||||||
integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==
|
integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==
|
||||||
|
|
||||||
|
"@sinclair/typebox@^0.25.16":
|
||||||
|
version "0.25.24"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718"
|
||||||
|
integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==
|
||||||
|
|
||||||
"@sinonjs/commons@^1.7.0":
|
"@sinonjs/commons@^1.7.0":
|
||||||
version "1.8.3"
|
version "1.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"
|
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"
|
||||||
@@ -10309,6 +10333,15 @@ jest-mock@^29.3.1:
|
|||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
jest-util "^29.3.1"
|
jest-util "^29.3.1"
|
||||||
|
|
||||||
|
jest-mock@^29.5.0:
|
||||||
|
version "29.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed"
|
||||||
|
integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==
|
||||||
|
dependencies:
|
||||||
|
"@jest/types" "^29.5.0"
|
||||||
|
"@types/node" "*"
|
||||||
|
jest-util "^29.5.0"
|
||||||
|
|
||||||
jest-pnp-resolver@^1.2.2:
|
jest-pnp-resolver@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
|
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
|
||||||
@@ -10451,6 +10484,18 @@ jest-util@^29.3.1:
|
|||||||
graceful-fs "^4.2.9"
|
graceful-fs "^4.2.9"
|
||||||
picomatch "^2.2.3"
|
picomatch "^2.2.3"
|
||||||
|
|
||||||
|
jest-util@^29.5.0:
|
||||||
|
version "29.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f"
|
||||||
|
integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==
|
||||||
|
dependencies:
|
||||||
|
"@jest/types" "^29.5.0"
|
||||||
|
"@types/node" "*"
|
||||||
|
chalk "^4.0.0"
|
||||||
|
ci-info "^3.2.0"
|
||||||
|
graceful-fs "^4.2.9"
|
||||||
|
picomatch "^2.2.3"
|
||||||
|
|
||||||
jest-validate@^29.2.2:
|
jest-validate@^29.2.2:
|
||||||
version "29.2.2"
|
version "29.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.2.2.tgz#e43ce1931292dfc052562a11bc681af3805eadce"
|
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.2.2.tgz#e43ce1931292dfc052562a11bc681af3805eadce"
|
||||||
|
|||||||
Reference in New Issue
Block a user