mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-03 20:53:20 -05:00
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 <lieut-data@users.noreply.github.com> (cherry picked from commit3a34196e47) * 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 <li>. SearchChannelSuggestion was connected with a null mapDispatchToProps, so react-redux injected dispatch, which the suggestion container then spread onto its <li>. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> (cherry picked from commit959ba3b90d) * 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 <li>. 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 <lieut-data@users.noreply.github.com> (cherry picked from commit41d09dfbfd) * 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 <lieut-data@users.noreply.github.com> (cherry picked from commita4025d5271) * fixup! webapp: let Tag forward a ref --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com>
This commit is contained in:
co-authored by
Cursor Agent
Jesse Hallam
parent
235bddbae0
commit
f6f2719165
@@ -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}
|
||||
|
||||
-1
@@ -37,7 +37,6 @@ interface Props extends Menu.FirstMenuItemProps {
|
||||
channel: Channel;
|
||||
user: UserProfile;
|
||||
isMuted: boolean;
|
||||
isReadonly: boolean;
|
||||
isDefault: boolean;
|
||||
isMobile: boolean;
|
||||
isFavorite: boolean;
|
||||
|
||||
+3
-2
@@ -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) => (
|
||||
<Menu.Item
|
||||
key={rc.remote_id}
|
||||
id={`${MENU_ID}-item-${rc.remote_id}`}
|
||||
key={`${rc.remote_id}-${rc.name}`}
|
||||
id={`${MENU_ID}-item-${rc.remote_id}-${rc.name}`}
|
||||
labels={<span>{rc.display_name || rc.name}</span>}
|
||||
onClick={() => handleSelect(rc)}
|
||||
/>
|
||||
|
||||
@@ -36,6 +36,10 @@ const SuggestionContainer = React.forwardRef<HTMLLIElement, SuggestionProps<unkn
|
||||
|
||||
Reflect.deleteProperty(otherProps, 'item');
|
||||
|
||||
// Suggestions are usually connected, and a connect() without mapDispatchToProps injects a
|
||||
// `dispatch` prop that the suggestion then forwards here along with the rest of its props.
|
||||
Reflect.deleteProperty(otherProps, 'dispatch');
|
||||
|
||||
const handleClick = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ const TagText = styled.span`
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
const Tag = ({
|
||||
const Tag = React.forwardRef<HTMLElement, Props>(({
|
||||
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 (
|
||||
<TagWrapper
|
||||
{...rest}
|
||||
|
||||
// TagWrapper renders a div or a button, but styled-components types
|
||||
// its ref as one or the other, never HTMLElement.
|
||||
ref={ref as React.Ref<HTMLDivElement>}
|
||||
as={element}
|
||||
uppercase={uppercase}
|
||||
onClick={onClick}
|
||||
@@ -166,6 +170,7 @@ const Tag = ({
|
||||
<TagText>{text}</TagText>
|
||||
</TagWrapper>
|
||||
);
|
||||
};
|
||||
});
|
||||
Tag.displayName = 'Tag';
|
||||
|
||||
export default memo(Tag);
|
||||
|
||||
Reference in New Issue
Block a user