Simplify widget detection
Use the exists check for the widget API directly instead of a feature flag.
This commit is contained in:
@@ -13,19 +13,14 @@ import { type FC, type PropsWithChildren } from "react";
|
|||||||
import { ClientContextProvider } from "./ClientContext";
|
import { ClientContextProvider } from "./ClientContext";
|
||||||
import { Avatar } from "./Avatar";
|
import { Avatar } from "./Avatar";
|
||||||
import { mockMatrixRoomMember, mockRtcMembership } from "./utils/test";
|
import { mockMatrixRoomMember, mockRtcMembership } from "./utils/test";
|
||||||
import EventEmitter from "events";
|
|
||||||
import { widget } from "./widget";
|
import { widget } from "./widget";
|
||||||
|
import { WidgetApi } from "matrix-widget-api";
|
||||||
|
|
||||||
const TestComponent: FC<
|
const TestComponent: FC<
|
||||||
PropsWithChildren<{
|
PropsWithChildren<{
|
||||||
client: MatrixClient;
|
client: MatrixClient;
|
||||||
supportsAuthenticatedMedia?: boolean;
|
|
||||||
}>
|
}>
|
||||||
> = ({
|
> = ({ client, children }) => {
|
||||||
client,
|
|
||||||
children,
|
|
||||||
supportsAuthenticatedMedia: supportsAuthenticatedMedia,
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<ClientContextProvider
|
<ClientContextProvider
|
||||||
value={{
|
value={{
|
||||||
@@ -33,7 +28,6 @@ const TestComponent: FC<
|
|||||||
disconnected: false,
|
disconnected: false,
|
||||||
supportedFeatures: {
|
supportedFeatures: {
|
||||||
reactions: true,
|
reactions: true,
|
||||||
authenticatedMedia: supportsAuthenticatedMedia ?? true,
|
|
||||||
},
|
},
|
||||||
setClient: vi.fn(),
|
setClient: vi.fn(),
|
||||||
authenticated: {
|
authenticated: {
|
||||||
@@ -51,7 +45,7 @@ const TestComponent: FC<
|
|||||||
|
|
||||||
vi.mock("./widget", () => ({
|
vi.mock("./widget", () => ({
|
||||||
widget: {
|
widget: {
|
||||||
api: { downloadFile: vi.fn() },
|
api: null, // Ideally we'd only mock this in the as a widget test so the whole module is otherwise null, but just nulling `api` by default works well enough
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -88,7 +82,7 @@ test("should just render a placeholder when the user has no avatar", () => {
|
|||||||
expect(client.mxcUrlToHttp).toBeCalledTimes(0);
|
expect(client.mxcUrlToHttp).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should attempt to fetch authenticated media if supported", async () => {
|
test("should attempt to fetch authenticated media from the server", async () => {
|
||||||
const expectedAuthUrl = "http://example.org/media/alice-avatar";
|
const expectedAuthUrl = "http://example.org/media/alice-avatar";
|
||||||
const expectedObjectURL = "my-object-url";
|
const expectedObjectURL = "my-object-url";
|
||||||
const accessToken = "my-access-token";
|
const accessToken = "my-access-token";
|
||||||
@@ -120,7 +114,7 @@ test("should attempt to fetch authenticated media if supported", async () => {
|
|||||||
);
|
);
|
||||||
const displayName = "Alice";
|
const displayName = "Alice";
|
||||||
render(
|
render(
|
||||||
<TestComponent client={client} supportsAuthenticatedMedia={true}>
|
<TestComponent client={client}>
|
||||||
<Avatar
|
<Avatar
|
||||||
id={member.userId}
|
id={member.userId}
|
||||||
name={displayName}
|
name={displayName}
|
||||||
@@ -141,7 +135,7 @@ test("should attempt to fetch authenticated media if supported", async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should attempt to use widget API if authenticate media is not supported", async () => {
|
test("should attempt to use widget API if running as a widget", async () => {
|
||||||
const expectedMXCUrl = "mxc://example.org/alice-avatar";
|
const expectedMXCUrl = "mxc://example.org/alice-avatar";
|
||||||
const expectedObjectURL = "my-object-url";
|
const expectedObjectURL = "my-object-url";
|
||||||
const theBlob = new Blob([]);
|
const theBlob = new Blob([]);
|
||||||
@@ -157,6 +151,7 @@ test("should attempt to use widget API if authenticate media is not supported",
|
|||||||
getAccessToken: () => undefined,
|
getAccessToken: () => undefined,
|
||||||
} as unknown as MatrixClient);
|
} as unknown as MatrixClient);
|
||||||
|
|
||||||
|
widget!.api = { downloadFile: vi.fn() } as unknown as WidgetApi;
|
||||||
vi.spyOn(widget!.api, "downloadFile").mockResolvedValue({ file: theBlob });
|
vi.spyOn(widget!.api, "downloadFile").mockResolvedValue({ file: theBlob });
|
||||||
const member = mockMatrixRoomMember(
|
const member = mockMatrixRoomMember(
|
||||||
mockRtcMembership("@alice:example.org", "AAAA"),
|
mockRtcMembership("@alice:example.org", "AAAA"),
|
||||||
@@ -166,7 +161,7 @@ test("should attempt to use widget API if authenticate media is not supported",
|
|||||||
);
|
);
|
||||||
const displayName = "Alice";
|
const displayName = "Alice";
|
||||||
render(
|
render(
|
||||||
<TestComponent client={client} supportsAuthenticatedMedia={false}>
|
<TestComponent client={client}>
|
||||||
<Avatar
|
<Avatar
|
||||||
id={member.userId}
|
id={member.userId}
|
||||||
name={displayName}
|
name={displayName}
|
||||||
|
|||||||
@@ -87,23 +87,23 @@ export const Avatar: FC<Props> = ({
|
|||||||
|
|
||||||
const [avatarUrl, setAvatarUrl] = useState<string | undefined>(undefined);
|
const [avatarUrl, setAvatarUrl] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
|
// In theory, a change in `clientState` or `sizePx` could run extra getAvatarFromWidgetAPI calls, but in practice they should be stable long before this code runs.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!src || clientState?.state !== "valid") {
|
if (!src) {
|
||||||
setAvatarUrl(undefined);
|
setAvatarUrl(undefined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { authenticated, supportedFeatures } = clientState;
|
|
||||||
let blob: Promise<Blob>;
|
let blob: Promise<Blob>;
|
||||||
|
|
||||||
if (
|
if (widget?.api) {
|
||||||
supportedFeatures.authenticatedMedia &&
|
blob = getAvatarFromWidgetAPI(widget.api, src);
|
||||||
authenticated?.client &&
|
} else if (
|
||||||
|
clientState?.state === "valid" &&
|
||||||
|
clientState.authenticated?.client &&
|
||||||
sizePx
|
sizePx
|
||||||
) {
|
) {
|
||||||
blob = getAvatarFromServer(authenticated.client, src, sizePx);
|
blob = getAvatarFromServer(clientState.authenticated.client, src, sizePx);
|
||||||
} else if (widget?.api) {
|
|
||||||
blob = getAvatarFromWidgetAPI(widget.api, src);
|
|
||||||
} else {
|
} else {
|
||||||
setAvatarUrl(undefined);
|
setAvatarUrl(undefined);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ export type ValidClientState = {
|
|||||||
disconnected: boolean;
|
disconnected: boolean;
|
||||||
supportedFeatures: {
|
supportedFeatures: {
|
||||||
reactions: boolean;
|
reactions: boolean;
|
||||||
authenticatedMedia: boolean;
|
|
||||||
};
|
};
|
||||||
setClient: (client: MatrixClient, session: Session) => void;
|
setClient: (client: MatrixClient, session: Session) => void;
|
||||||
};
|
};
|
||||||
@@ -249,8 +248,6 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
|||||||
|
|
||||||
const [isDisconnected, setIsDisconnected] = useState(false);
|
const [isDisconnected, setIsDisconnected] = useState(false);
|
||||||
const [supportsReactions, setSupportsReactions] = useState(false);
|
const [supportsReactions, setSupportsReactions] = useState(false);
|
||||||
const [supportsAuthenticatedMedia, setSupportsAuthenticatedMedia] =
|
|
||||||
useState(false);
|
|
||||||
|
|
||||||
const state: ClientState | undefined = useMemo(() => {
|
const state: ClientState | undefined = useMemo(() => {
|
||||||
if (alreadyOpenedErr) {
|
if (alreadyOpenedErr) {
|
||||||
@@ -276,7 +273,6 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
|||||||
disconnected: isDisconnected,
|
disconnected: isDisconnected,
|
||||||
supportedFeatures: {
|
supportedFeatures: {
|
||||||
reactions: supportsReactions,
|
reactions: supportsReactions,
|
||||||
authenticatedMedia: supportsAuthenticatedMedia,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
@@ -287,7 +283,6 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
|||||||
setClient,
|
setClient,
|
||||||
isDisconnected,
|
isDisconnected,
|
||||||
supportsReactions,
|
supportsReactions,
|
||||||
supportsAuthenticatedMedia,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const onSync = useCallback(
|
const onSync = useCallback(
|
||||||
@@ -313,8 +308,6 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (initClientState.widgetApi) {
|
if (initClientState.widgetApi) {
|
||||||
// There is currently no way for widgets to request authenticated media directly from the server.
|
|
||||||
setSupportsAuthenticatedMedia(false);
|
|
||||||
const reactSend = initClientState.widgetApi.hasCapability(
|
const reactSend = initClientState.widgetApi.hasCapability(
|
||||||
"org.matrix.msc2762.send.event:m.reaction",
|
"org.matrix.msc2762.send.event:m.reaction",
|
||||||
);
|
);
|
||||||
@@ -336,7 +329,6 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setSupportsReactions(true);
|
setSupportsReactions(true);
|
||||||
setSupportsAuthenticatedMedia(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (): void => {
|
return (): void => {
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ function renderWithMockClient(
|
|||||||
disconnected: false,
|
disconnected: false,
|
||||||
supportedFeatures: {
|
supportedFeatures: {
|
||||||
reactions: true,
|
reactions: true,
|
||||||
authenticatedMedia: true,
|
|
||||||
},
|
},
|
||||||
setClient: vi.fn(),
|
setClient: vi.fn(),
|
||||||
authenticated: {
|
authenticated: {
|
||||||
|
|||||||
Reference in New Issue
Block a user