Skip to content

Update custom component logic to always return a hint. #30321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/components/views/elements/ImageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -606,9 +606,12 @@
setCanDownload(true);
return;
}
// Get the hint. If the hint is static then we can immediately set it,
// otherwise set to false until the promise completes.
const hints = ModuleApi.customComponents.getHintsForMessage(mxEvent);
if (hints?.allowDownloadingMedia) {
// Disable downloading as soon as we know there is a hint.
if (typeof hints.allowDownloadingMedia === "boolean") {
setCanDownload(hints.allowDownloadingMedia);
} else {
setCanDownload(false);
hints
.allowDownloadingMedia()
Expand All @@ -620,7 +623,7 @@
// Err on the side of safety.
setCanDownload(false);
});
}

Check failure on line 626 in src/components/views/elements/ImageView.tsx

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Declaration or statement expected.
}, [mxEvent]);

function showError(e: unknown): void {
Expand Down
23 changes: 11 additions & 12 deletions src/components/views/messages/DownloadActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,21 @@ export default class DownloadActionButton extends React.PureComponent<IProps, IS
public constructor(props: IProps) {
super(props);

const moduleHints = ModuleApi.customComponents.getHintsForMessage(props.mxEvent);
const downloadState: Pick<IState, "canDownload"> = { canDownload: true };
if (moduleHints?.allowDownloadingMedia) {
downloadState.canDownload = null;
moduleHints
const hints = ModuleApi.customComponents.getHintsForMessage(props.mxEvent);
const downloadState: Pick<IState, "canDownload"> = { canDownload: null };
if (typeof hints.allowDownloadingMedia === "boolean") {
downloadState.canDownload = hints.allowDownloadingMedia;
} else {
downloadState.canDownload = false;
hints
.allowDownloadingMedia()
.then((canDownload) => {
this.setState({
canDownload: canDownload,
});
.then((downloadable) => {
this.setState({ canDownload: downloadable });
})
.catch((ex) => {
logger.error(`Failed to check if media from ${props.mxEvent.getId()} could be downloaded`, ex);
this.setState({
canDownload: false,
});
// Err on the side of safety.
this.setState({ canDownload: false });
});
}

Expand Down
4 changes: 1 addition & 3 deletions src/events/EventTileFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,7 @@ export function haveRendererForEvent(
return false;
}

// Check to see if we have any hints for this message, which indicates
// there is a custom renderer for the event.
if (ModuleApi.customComponents.getHintsForMessage(mxEvent)) {
if (ModuleApi.customComponents.hasRendererForEvent(mxEvent)) {
return true;
}

Expand Down
42 changes: 28 additions & 14 deletions src/modules/customComponentApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ interface CustomMessageComponentProps extends Omit<ModuleCustomMessageComponentP
}

interface CustomMessageRenderHints extends Omit<ModuleCustomCustomMessageRenderHints, "allowDownloadingMedia"> {
// Note. This just makes it easier to use this API on Element Web as we already have the moduleized event stored.
allowDownloadingMedia?: () => Promise<boolean>;
// Note. This just makes it easier to use this API on Element Web as we already have the modularized event stored.
allowDownloadingMedia?: (() => Promise<boolean>) | boolean;
}

const DEFAULT_HINTS: Required<CustomMessageRenderHints> = {
allowEditingEvent: true,
allowDownloadingMedia: true,
};

export class CustomComponentsApi implements ICustomComponentsApi {
/**
* Convert a matrix-js-sdk event into a ModuleMatrixEvent.
Expand Down Expand Up @@ -115,23 +120,32 @@ export class CustomComponentsApi implements ICustomComponentsApi {
return originalComponent?.() ?? null;
}

/**
* Has a custom component been registered for this event.
* @param mxEvent
* @returns `true` if a component has been registered and would be rendered, otherwise false.
*/
public hasRendererForEvent(mxEvent: MatrixEvent): boolean {
const moduleEv = CustomComponentsApi.getModuleMatrixEvent(mxEvent);
return !!(moduleEv && this.selectRenderer(moduleEv));
}

/**
* Get hints about an message before rendering it.
* @param mxEvent The message event being rendered.
* @returns A component if a custom renderer exists, or originalComponent returns a value. Otherwise null.
* @returns A set of hints to use when rendering messages, provided by custom renderers. If a hint
* is not provided by a renderer, or no renderers are present then `DEFAULT_HINTS` are used.
*/
public getHintsForMessage(mxEvent: MatrixEvent): CustomMessageRenderHints | null {
public getHintsForMessage(mxEvent: MatrixEvent): Required<CustomMessageRenderHints> {
const moduleEv = CustomComponentsApi.getModuleMatrixEvent(mxEvent);
const renderer = moduleEv && this.selectRenderer(moduleEv);
if (renderer) {
return {
...renderer.hints,
// Convert from js-sdk style events to module events automatically.
allowDownloadingMedia: renderer.hints.allowDownloadingMedia
? () => renderer.hints.allowDownloadingMedia!(moduleEv)
: undefined,
};
}
return null;
return {
...DEFAULT_HINTS,
...renderer?.hints,
// Convert from js-sdk style events to module events automatically.
allowDownloadingMedia: renderer?.hints.allowDownloadingMedia
? () => renderer.hints.allowDownloadingMedia!(moduleEv!)
: DEFAULT_HINTS.allowDownloadingMedia,
};
}
}
Loading