Pillify event permalinks (#10392)

This commit is contained in:
Michael Weimann
2023-03-21 10:23:20 +01:00
committed by GitHub
parent d8acdd1750
commit 96d1b74ffc
19 changed files with 742 additions and 144 deletions

View File

@@ -14,16 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { logger } from "matrix-js-sdk/src/logger";
import { MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { useCallback, useMemo, useState } from "react";
import { Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { ButtonEvent } from "../components/views/elements/AccessibleButton";
import { PillType } from "../components/views/elements/Pill";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { parsePermalink } from "../utils/permalinks/Permalinks";
import dis from "../dispatcher/dispatcher";
import { Action } from "../dispatcher/actions";
import { PermalinkParts } from "../utils/permalinks/PermalinkConstructor";
import { _t } from "../languageHandler";
import { usePermalinkTargetRoom } from "./usePermalinkTargetRoom";
import { usePermalinkEvent } from "./usePermalinkEvent";
import { usePermalinkMember } from "./usePermalinkMember";
interface Args {
/** Room in which the permalink should be displayed. */
@@ -71,97 +73,77 @@ interface HookResult {
}
/**
* Can be used to retrieve all information to display a permalink.
* Tries to determine the pill type.
*
* If forcedType is present it will be returned.
* If the parse result contains a room Id or alias and an event Id:
* - Type is EventInSameRoom if the permalink room Id or alias equals the parsed room Id or alias
* - Type is EventInOtherRoom if the permalink room Id or alias not equals the parsed room Id or alias
* If the parse result contains a primary entity Id it will try to detect the type from it.
* Otherwise returns null.
*
* @param forcedType - Forced pill type. Will be used if present and short-circuits all othe conditions.
* @param parseResult - Permalink parser result
* @param permalinkRoom - Room in which the permalink is displayed.
* @returns Pill type or null if unable to determine.
*/
export const usePermalink: (args: Args) => HookResult = ({ room, type: argType, url }): HookResult => {
const [member, setMember] = useState<RoomMember | null>(null);
// room of the entity this pill points to
const [targetRoom, setTargetRoom] = useState<Room | null>(room ?? null);
const determineType = (
forcedType: PillType | undefined,
parseResult: PermalinkParts | null,
permalinkRoom: Room | undefined,
): PillType | null => {
if (forcedType) return forcedType;
if (parseResult?.roomIdOrAlias && parseResult?.eventId) {
if (parseResult.roomIdOrAlias === permalinkRoom?.roomId) {
return PillType.EventInSameRoom;
}
return PillType.EventInOtherRoom;
}
if (parseResult?.primaryEntityId) {
const prefix = parseResult.primaryEntityId[0] || "";
return (
{
"@": PillType.UserMention,
"#": PillType.RoomMention,
"!": PillType.RoomMention,
}[prefix] || null
);
}
return null;
};
/**
* Can be used to retrieve all information needed to display a permalink.
*/
export const usePermalink: (args: Args) => HookResult = ({
room: permalinkRoom,
type: forcedType,
url,
}): HookResult => {
let resourceId: string | null = null;
let parseResult: PermalinkParts | null = null;
if (url) {
const parseResult = parsePermalink(url);
parseResult = parsePermalink(url);
if (parseResult?.primaryEntityId) {
resourceId = parseResult.primaryEntityId;
}
}
const prefix = resourceId ? resourceId[0] : "";
const type =
argType ||
// try to detect the permalink type from the URL prefix
{
"@": PillType.UserMention,
"#": PillType.RoomMention,
"!": PillType.RoomMention,
}[prefix] ||
null;
const doProfileLookup = useCallback((userId: string, member: RoomMember): void => {
MatrixClientPeg.get()
.getProfileInfo(userId)
.then((resp) => {
const newMember = new RoomMember(member.roomId, userId);
newMember.name = resp.displayname || userId;
newMember.rawDisplayName = resp.displayname || userId;
newMember.getMxcAvatarUrl();
newMember.events.member = {
getContent: () => {
return { avatar_url: resp.avatar_url };
},
getDirectionalContent: function () {
// eslint-disable-next-line
return this.getContent();
},
} as MatrixEvent;
setMember(newMember);
})
.catch((err) => {
logger.error("Could not retrieve profile data for " + userId + ":", err);
});
}, []);
useMemo(() => {
switch (type) {
case PillType.UserMention:
{
if (resourceId) {
let member = room?.getMember(resourceId) || null;
setMember(member);
if (!member) {
member = new RoomMember("", resourceId);
doProfileLookup(resourceId, member);
}
}
}
break;
case PillType.RoomMention:
{
if (resourceId) {
const newRoom =
resourceId[0] === "#"
? MatrixClientPeg.get()
.getRooms()
.find((r) => {
return (
r.getCanonicalAlias() === resourceId ||
(resourceId && r.getAltAliases().includes(resourceId))
);
})
: MatrixClientPeg.get().getRoom(resourceId);
setTargetRoom(newRoom || null);
}
}
break;
}
}, [doProfileLookup, type, resourceId, room]);
const type = determineType(forcedType, parseResult, permalinkRoom);
const targetRoom = usePermalinkTargetRoom(type, parseResult, permalinkRoom);
const event = usePermalinkEvent(type, parseResult, targetRoom);
const member = usePermalinkMember(type, parseResult, targetRoom, event);
let onClick: (e: ButtonEvent) => void = () => {};
let text = resourceId;
if (type === PillType.AtRoomMention && room) {
if (type === PillType.AtRoomMention && permalinkRoom) {
text = "@room";
} else if (type === PillType.UserMention && member) {
text = member.name || resourceId;
@@ -177,6 +159,10 @@ export const usePermalink: (args: Args) => HookResult = ({ room, type: argType,
if (targetRoom) {
text = targetRoom.name || resourceId;
}
} else if (type === PillType.EventInSameRoom) {
text = member?.name || _t("User");
} else if (type === PillType.EventInOtherRoom) {
text = targetRoom?.name || _t("Room");
}
return {