From 263884cbd86326ed48a6b69c937ff35dec2d529b Mon Sep 17 00:00:00 2001 From: V Date: Tue, 16 May 2023 00:19:20 +0200 Subject: [PATCH] PermViewer: Fix context menu for roleless users & muted channels (#1138) Co-authored-by: V Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com> --- src/api/ContextMenu.ts | 17 +++++++------ src/plugins/permissionsViewer/index.tsx | 31 +++++++++++++++--------- src/plugins/permissionsViewer/styles.css | 3 ++- src/plugins/searchReply.tsx | 2 +- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/api/ContextMenu.ts b/src/api/ContextMenu.ts index f1ebfdb..156ae20 100644 --- a/src/api/ContextMenu.ts +++ b/src/api/ContextMenu.ts @@ -25,14 +25,14 @@ type ContextMenuPatchCallbackReturn = (() => void) | void; * @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example * @returns A callback which is only ran once used to modify the context menu elements (Use to avoid duplicates) */ -export type NavContextMenuPatchCallback = (children: Array, ...args: Array) => ContextMenuPatchCallbackReturn; +export type NavContextMenuPatchCallback = (children: Array, ...args: Array) => ContextMenuPatchCallbackReturn; /** * @param navId The navId of the context menu being patched * @param children The rendered context menu elements * @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example * @returns A callback which is only ran once used to modify the context menu elements (Use to avoid duplicates) */ -export type GlobalContextMenuPatchCallback = (navId: string, children: Array, ...args: Array) => ContextMenuPatchCallbackReturn; +export type GlobalContextMenuPatchCallback = (navId: string, children: Array, ...args: Array) => ContextMenuPatchCallbackReturn; const ContextMenuLogger = new Logger("ContextMenu"); @@ -89,15 +89,18 @@ export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallba } /** - * A helper function for finding the children array of a group nested inside a context menu based on the id of one of its childs - * @param id The id of the child + * A helper function for finding the children array of a group nested inside a context menu based on the id(s) of its children + * @param id The id of the child. If an array is specified, all ids will be tried * @param children The context menu children */ -export function findGroupChildrenByChildId(id: string, children: Array, _itemsArray?: Array): Array | null { +export function findGroupChildrenByChildId(id: string | string[], children: Array, _itemsArray?: Array): Array | null { for (const child of children) { if (child == null) continue; - if (child.props?.id === id) return _itemsArray ?? null; + if ( + (Array.isArray(id) && id.some(id => child.props?.id === id)) + || child.props?.id === id + ) return _itemsArray ?? null; let nextChildren = child.props?.children; if (nextChildren) { @@ -117,7 +120,7 @@ export function findGroupChildrenByChildId(id: string, children: Array; navId: string; - children: Array; + children: Array; "aria-label": string; onSelect: (() => void) | undefined; onClose: (callback: (...args: Array) => any) => void; diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx index 793105a..208fef3 100644 --- a/src/plugins/permissionsViewer/index.tsx +++ b/src/plugins/permissionsViewer/index.tsx @@ -57,6 +57,8 @@ export const settings = definePluginSettings({ }); function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) { + if (type === MenuItemParentType.User && !GuildMemberStore.isMember(guildId, id!)) return null; + return ( () => { if (!props) return children; const group = findGroupChildrenByChildId(childId, children); - if (group) { + const item = (() => { switch (type) { case MenuItemParentType.User: - group.push(MenuItem(props.guildId, props.user.id, type)); - break; + return MenuItem(props.guildId, props.user.id, type); case MenuItemParentType.Channel: - group.push(MenuItem(props.guild.id, props.channel.id, type)); - break; + return MenuItem(props.guild.id, props.channel.id, type); case MenuItemParentType.Guild: - group.push(MenuItem(props.guild.id)); - break; + return MenuItem(props.guild.id); + default: + return null; } - } + })(); + + if (item == null) return; + + if (group) + group.push(item); + else if (childId === "roles" && props.guildId) + // "roles" may not be present due to the member not having any roles. In that case, add it above "Copy ID" + children.splice(-1, 0, {item}); }; } @@ -160,10 +169,10 @@ export default definePlugin({ } ], - UserPermissions: (guild: Guild, guildMember: GuildMember) => , + UserPermissions: (guild: Guild, guildMember?: GuildMember) => !!guildMember && , userContextMenuPatch: makeContextMenuPatch("roles", MenuItemParentType.User), - channelContextMenuPatch: makeContextMenuPatch("mute-channel", MenuItemParentType.Channel), + channelContextMenuPatch: makeContextMenuPatch(["mute-channel", "unmute-channel"], MenuItemParentType.Channel), guildContextMenuPatch: makeContextMenuPatch("privacy", MenuItemParentType.Guild), start() { diff --git a/src/plugins/permissionsViewer/styles.css b/src/plugins/permissionsViewer/styles.css index 6d6c137..08e5e1c 100644 --- a/src/plugins/permissionsViewer/styles.css +++ b/src/plugins/permissionsViewer/styles.css @@ -59,7 +59,7 @@ align-items: center; padding: 8px 5px; cursor: pointer; - width: 165px; + width: 230px; } .vc-permviewer-perms-list-item > div { @@ -121,6 +121,7 @@ position: absolute; right: 0; scale: 0.9; + transition: color ease-in 0.1s; } .vc-permviewer-perms-perms-item .vc-info-icon:hover { diff --git a/src/plugins/searchReply.tsx b/src/plugins/searchReply.tsx index fe6348b..9e53436 100644 --- a/src/plugins/searchReply.tsx +++ b/src/plugins/searchReply.tsx @@ -38,7 +38,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag // dms and group chats const dmGroup = findGroupChildrenByChildId("pin", children); if (dmGroup && !dmGroup.some(child => child?.props?.id === "reply")) { - const pinIndex = dmGroup.findIndex(c => c.props.id === "pin"); + const pinIndex = dmGroup.findIndex(c => c?.props.id === "pin"); return dmGroup.splice(pinIndex + 1, 0, (