From f6f2719165ffb132e351342add570f3b1b6fd07a Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Wed, 2 Sep 2026 13:53:32 -0300 Subject: [PATCH] Fix props, refs and keys that React was warning about (#38238) * webapp: let Tag forward a ref WithTooltip anchors its popover by cloning its child with a ref. Tag is a function component, so the ref was dropped and React warned about it, leaving the marketplace label tooltips without a positioning reference. Co-authored-by: Jesse Hallam (cherry picked from commit 3a34196e47a9a875a8ef4b68227d9c3a94045725) * webapp: stop leaking component props onto DOM elements isReadonly was hardcoded to false, never read, and fell through a prop spread onto the channel header menu's
  • . SearchChannelSuggestion was connected with a null mapDispatchToProps, so react-redux injected dispatch, which the suggestion container then spread onto its
  • . Co-authored-by: Jesse Hallam (cherry picked from commit 959ba3b90d997be0cc0df6063a6dc07d626f2a6c) * webapp: stop connect's injected dispatch reaching suggestion list items Suggestions are connected components that forward their rest props into SuggestionContainer, which spreads them onto its
  • . A connect() without a mapDispatchToProps injects dispatch, so React saw it as an invalid DOM attribute. Drop it in the container alongside item, which covers every suggestion rather than one call site. Co-authored-by: Jesse Hallam (cherry picked from commit 41d09dfbfd694bdadcecc44b636f20630137984f) * webapp: key the add-workspace menu on a remote cluster's full identity RemoteClusters is keyed on (RemoteId, Name), so the same remote_id can appear more than once in the dropdown and React reported duplicate keys. Co-authored-by: Jesse Hallam (cherry picked from commit a4025d52718aa7504d2202101a8b9299daa27498) * fixup! webapp: let Tag forward a ref --------- Co-authored-by: Cursor Agent Co-authored-by: Jesse Hallam --- .../channel_header_menu/channel_header_menu.tsx | 3 --- .../channel_header_public_private_menu.tsx | 1 - .../add_workspace_dropdown.tsx | 5 +++-- .../channels/src/components/suggestion/suggestion.tsx | 4 ++++ webapp/channels/src/components/widgets/tag/tag.tsx | 11 ++++++++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/webapp/channels/src/components/channel_header_menu/channel_header_menu.tsx b/webapp/channels/src/components/channel_header_menu/channel_header_menu.tsx index ab1a2f5fc52..c7d6f2badb1 100644 --- a/webapp/channels/src/components/channel_header_menu/channel_header_menu.tsx +++ b/webapp/channels/src/components/channel_header_menu/channel_header_menu.tsx @@ -62,8 +62,6 @@ export default function ChannelHeaderMenu({dmUser, gmMembers, isMobile, archived const isChannelBookmarksEnabled = useSelector(getIsChannelBookmarksEnabled); const isChannelAutotranslated = useSelector((state: GlobalState) => (channel?.id ? isChannelAutotranslatedSelector(state, channel.id) : false)); - const isReadonly = false; - if (!channel) { return null; } @@ -181,7 +179,6 @@ export default function ChannelHeaderMenu({dmUser, gmMembers, isMobile, archived isFavorite={isFavorite} isMobile={isMobile || false} isDefault={isDefault} - isReadonly={isReadonly} isLicensedForLDAPGroups={isLicensedForLDAPGroups} isChannelBookmarksEnabled={isChannelBookmarksEnabled} isChannelAutotranslated={isChannelAutotranslated} diff --git a/webapp/channels/src/components/channel_header_menu/channel_header_menu_items/channel_header_public_private_menu.tsx b/webapp/channels/src/components/channel_header_menu/channel_header_menu_items/channel_header_public_private_menu.tsx index 6762597792d..56203be2868 100644 --- a/webapp/channels/src/components/channel_header_menu/channel_header_menu_items/channel_header_public_private_menu.tsx +++ b/webapp/channels/src/components/channel_header_menu/channel_header_menu_items/channel_header_public_private_menu.tsx @@ -37,7 +37,6 @@ interface Props extends Menu.FirstMenuItemProps { channel: Channel; user: UserProfile; isMuted: boolean; - isReadonly: boolean; isDefault: boolean; isMobile: boolean; isFavorite: boolean; diff --git a/webapp/channels/src/components/channel_settings_modal/share_channel_with_workspaces/add_workspace_dropdown.tsx b/webapp/channels/src/components/channel_settings_modal/share_channel_with_workspaces/add_workspace_dropdown.tsx index c2222068bef..48b3e01b768 100644 --- a/webapp/channels/src/components/channel_settings_modal/share_channel_with_workspaces/add_workspace_dropdown.tsx +++ b/webapp/channels/src/components/channel_settings_modal/share_channel_with_workspaces/add_workspace_dropdown.tsx @@ -97,10 +97,11 @@ export default function AddWorkspaceDropdown({ disabled={true} /> )} + {/* A remote cluster is keyed on (remote_id, name), so remote_id alone can repeat here. */} {!loading && available.map((rc) => ( {rc.display_name || rc.name}} onClick={() => handleSelect(rc)} /> diff --git a/webapp/channels/src/components/suggestion/suggestion.tsx b/webapp/channels/src/components/suggestion/suggestion.tsx index fa84052eca0..e8b10effe97 100644 --- a/webapp/channels/src/components/suggestion/suggestion.tsx +++ b/webapp/channels/src/components/suggestion/suggestion.tsx @@ -36,6 +36,10 @@ const SuggestionContainer = React.forwardRef { e.preventDefault(); diff --git a/webapp/channels/src/components/widgets/tag/tag.tsx b/webapp/channels/src/components/widgets/tag/tag.tsx index cdedf4b7c12..33039b2deb7 100644 --- a/webapp/channels/src/components/widgets/tag/tag.tsx +++ b/webapp/channels/src/components/widgets/tag/tag.tsx @@ -127,7 +127,7 @@ const TagText = styled.span` text-overflow: ellipsis; `; -const Tag = ({ +const Tag = React.forwardRef(({ variant, onClick, className, @@ -136,7 +136,7 @@ const Tag = ({ size = 'xs', uppercase = false, ...rest -}: Props) => { +}, ref) => { const Icon = iconName ? glyphMap[iconName] : null; const element = onClick ? 'button' : 'div'; @@ -157,6 +157,10 @@ const Tag = ({ return ( } as={element} uppercase={uppercase} onClick={onClick} @@ -166,6 +170,7 @@ const Tag = ({ {text} ); -}; +}); +Tag.displayName = 'Tag'; export default memo(Tag);