Page MenuHomePhabricator

D9638.id32595.diff
No OneTemporary

D9638.id32595.diff

diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js
--- a/lib/shared/message-utils.js
+++ b/lib/shared/message-utils.js
@@ -41,7 +41,7 @@
RawReactionMessageInfo,
ReactionMessageInfo,
} from '../types/messages/reaction.js';
-import { type ThreadInfo } from '../types/thread-types.js';
+import type { ThreadInfo } from '../types/thread-types.js';
import type { UserInfos } from '../types/user-types.js';
import {
type EntityText,
@@ -665,8 +665,24 @@
);
}
-function isInvalidPinSource(message: RawMessageInfo | MessageInfo): boolean {
- return !messageSpecs[message.type].canBePinned;
+// Prefer checking isInvalidPinSourceForThread below. This function doesn't
+// check whether the user is attempting to pin a SIDEBAR_SOURCE in the context
+// of its parent thread, so it's not suitable for permission checks. We only
+// use it in the message-fetchers.js code where we don't have access to the
+// RawThreadInfo and don't need to do permission checks.
+function isInvalidPinSource(
+ messageInfo: RawMessageInfo | MessageInfo,
+): boolean {
+ return !messageSpecs[messageInfo.type].canBePinned;
+}
+
+function isInvalidPinSourceForThread(
+ messageInfo: RawMessageInfo | MessageInfo,
+ threadInfo: ThreadInfo,
+): boolean {
+ const isValidPinSource = !isInvalidPinSource(messageInfo);
+ const isFirstMessageInSidebar = threadInfo.sourceMessageID === messageInfo.id;
+ return !isValidPinSource || isFirstMessageInSidebar;
}
function isUnableToBeRenderedIndependently(
@@ -706,5 +722,6 @@
useNextLocalID,
isInvalidSidebarSource,
isInvalidPinSource,
+ isInvalidPinSourceForThread,
isUnableToBeRenderedIndependently,
};
diff --git a/lib/utils/toggle-pin-utils.js b/lib/utils/toggle-pin-utils.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/toggle-pin-utils.js
@@ -0,0 +1,25 @@
+// @flow
+
+import { isInvalidPinSourceForThread } from '../shared/message-utils.js';
+import { threadHasPermission } from '../shared/thread-utils.js';
+import type {
+ ComposableMessageInfo,
+ RobotextMessageInfo,
+} from '../types/message-types.js';
+import { threadPermissions } from '../types/thread-permission-types.js';
+import type { ThreadInfo } from '../types/thread-types.js';
+
+function canToggleMessagePin(
+ messageInfo: ComposableMessageInfo | RobotextMessageInfo,
+ threadInfo: ThreadInfo,
+): boolean {
+ const isValidMessage = !isInvalidPinSourceForThread(messageInfo, threadInfo);
+ const hasManagePinsPermission = threadHasPermission(
+ threadInfo,
+ threadPermissions.MANAGE_PINS,
+ );
+
+ return isValidMessage && hasManagePinsPermission;
+}
+
+export { canToggleMessagePin };
diff --git a/native/chat/message-results-screen.react.js b/native/chat/message-results-screen.react.js
--- a/native/chat/message-results-screen.react.js
+++ b/native/chat/message-results-screen.react.js
@@ -9,7 +9,7 @@
import { messageListData } from 'lib/selectors/chat-selectors.js';
import {
createMessageInfo,
- isInvalidPinSource,
+ isInvalidPinSourceForThread,
} from 'lib/shared/message-utils.js';
import type { ThreadInfo } from 'lib/types/thread-types.js';
import { useServerCall } from 'lib/utils/action-utils.js';
@@ -77,7 +77,7 @@
item =>
item.itemType === 'message' &&
item.isPinned &&
- !isInvalidPinSource(item.messageInfo),
+ !isInvalidPinSourceForThread(item.messageInfo, threadInfo),
);
// By the nature of using messageListData and passing in
@@ -102,7 +102,7 @@
}
return sortedChatMessageInfoItems.filter(Boolean);
- }, [chatMessageInfos, rawMessageResults]);
+ }, [chatMessageInfos, rawMessageResults, threadInfo]);
const measureCallback = React.useCallback(
(listDataWithHeights: $ReadOnlyArray<ChatMessageItemWithHeight>) => {
diff --git a/native/chat/message.react.js b/native/chat/message.react.js
--- a/native/chat/message.react.js
+++ b/native/chat/message.react.js
@@ -8,6 +8,7 @@
} from 'react-native';
import { messageKey } from 'lib/shared/message-utils.js';
+import { canToggleMessagePin } from 'lib/utils/toggle-pin-utils.js';
import type { ChatNavigationProp } from './chat.react.js';
import MultimediaMessage from './multimedia-message.react.js';
@@ -91,6 +92,11 @@
[focused, item],
);
+ const canTogglePins = React.useMemo(
+ () => canToggleMessagePin(props.item.messageInfo, props.item.threadInfo),
+ [props.item.messageInfo, props.item.threadInfo],
+ );
+
const innerMessageNode = React.useMemo(() => {
if (item.messageShapeType === 'text') {
return (
@@ -101,6 +107,7 @@
focused={focused}
toggleFocus={toggleFocus}
verticalBounds={verticalBounds}
+ canTogglePins={canTogglePins}
shouldDisplayPinIndicator={shouldDisplayPinIndicator}
/>
);
@@ -111,6 +118,7 @@
focused={focused}
toggleFocus={toggleFocus}
verticalBounds={verticalBounds}
+ canTogglePins={canTogglePins}
shouldDisplayPinIndicator={shouldDisplayPinIndicator}
/>
);
@@ -134,6 +142,7 @@
shouldDisplayPinIndicator,
toggleFocus,
verticalBounds,
+ canTogglePins,
]);
const message = React.useMemo(
diff --git a/native/chat/multimedia-message.react.js b/native/chat/multimedia-message.react.js
--- a/native/chat/multimedia-message.react.js
+++ b/native/chat/multimedia-message.react.js
@@ -9,13 +9,9 @@
import * as React from 'react';
import { View } from 'react-native';
-import { isInvalidPinSource, messageKey } from 'lib/shared/message-utils.js';
-import {
- threadHasPermission,
- useCanCreateSidebarFromMessage,
-} from 'lib/shared/thread-utils.js';
+import { messageKey } from 'lib/shared/message-utils.js';
+import { useCanCreateSidebarFromMessage } from 'lib/shared/thread-utils.js';
import type { MediaInfo } from 'lib/types/media-types.js';
-import { threadPermissions } from 'lib/types/thread-permission-types.js';
import ComposedMessage from './composed-message.react.js';
import { InnerMultimediaMessage } from './inner-multimedia-message.react.js';
@@ -45,6 +41,7 @@
+focused: boolean,
+toggleFocus: (messageKey: string) => void,
+verticalBounds: ?VerticalBounds,
+ +canTogglePins: boolean,
+shouldDisplayPinIndicator: boolean,
};
type Props = {
@@ -54,7 +51,6 @@
+overlayContext: ?OverlayContextType,
+chatContext: ?ChatContextType,
+canCreateSidebarFromMessage: boolean,
- +canTogglePins: boolean,
};
type State = {
+clickable: boolean,
@@ -242,13 +238,6 @@
props.item.threadInfo,
props.item.messageInfo,
);
- const canTogglePins =
- !isInvalidPinSource(props.item.messageInfo) &&
- threadHasPermission(
- props.item.threadInfo,
- threadPermissions.MANAGE_PINS,
- ) &&
- props.item.threadInfo.sourceMessageID !== props.item.messageInfo.id;
return (
<MultimediaMessage
@@ -258,7 +247,6 @@
overlayContext={overlayContext}
chatContext={chatContext}
canCreateSidebarFromMessage={canCreateSidebarFromMessage}
- canTogglePins={canTogglePins}
/>
);
});
diff --git a/native/chat/text-message.react.js b/native/chat/text-message.react.js
--- a/native/chat/text-message.react.js
+++ b/native/chat/text-message.react.js
@@ -4,7 +4,7 @@
import * as React from 'react';
import { View } from 'react-native';
-import { isInvalidPinSource, messageKey } from 'lib/shared/message-utils.js';
+import { messageKey } from 'lib/shared/message-utils.js';
import {
threadHasPermission,
useCanCreateSidebarFromMessage,
@@ -51,6 +51,7 @@
+focused: boolean,
+toggleFocus: (messageKey: string) => void,
+verticalBounds: ?VerticalBounds,
+ +canTogglePins: boolean,
+shouldDisplayPinIndicator: boolean,
};
type Props = {
@@ -65,7 +66,6 @@
+isLinkModalActive: boolean,
+isUserProfileBottomSheetActive: boolean,
+canEditMessage: boolean,
- +canTogglePins: boolean,
};
class TextMessage extends React.PureComponent<Props> {
message: ?React.ElementRef<typeof View>;
@@ -291,14 +291,6 @@
useCanEditMessageNative(props.item.threadInfo, props.item.messageInfo) &&
!isThisMessageEdited;
- const canTogglePins =
- !isInvalidPinSource(props.item.messageInfo) &&
- threadHasPermission(
- props.item.threadInfo,
- threadPermissions.MANAGE_PINS,
- ) &&
- props.item.threadInfo.sourceMessageID !== props.item.messageInfo.id;
-
React.useEffect(() => clearMarkdownContextData, [clearMarkdownContextData]);
return (
@@ -310,7 +302,6 @@
isLinkModalActive={isLinkModalActive}
isUserProfileBottomSheetActive={isUserProfileBottomSheetActive}
canEditMessage={canEditMessage}
- canTogglePins={canTogglePins}
/>
);
});
diff --git a/web/modals/chat/message-results-modal.react.js b/web/modals/chat/message-results-modal.react.js
--- a/web/modals/chat/message-results-modal.react.js
+++ b/web/modals/chat/message-results-modal.react.js
@@ -11,7 +11,7 @@
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import {
createMessageInfo,
- isInvalidPinSource,
+ isInvalidPinSourceForThread,
modifyItemForResultScreen,
} from 'lib/shared/message-utils.js';
import { type ThreadInfo } from 'lib/types/thread-types.js';
@@ -80,7 +80,7 @@
item =>
item.itemType === 'message' &&
item.isPinned &&
- !isInvalidPinSource(item.messageInfo),
+ !isInvalidPinSourceForThread(item.messageInfo, threadInfo),
);
// By the nature of using messageListData and passing in
@@ -105,7 +105,7 @@
}
return sortedChatMessageInfoItems;
- }, [chatMessageInfos, rawMessageResults]);
+ }, [chatMessageInfos, rawMessageResults, threadInfo]);
const modifiedItems = React.useMemo(
() =>
diff --git a/web/utils/tooltip-action-utils.js b/web/utils/tooltip-action-utils.js
--- a/web/utils/tooltip-action-utils.js
+++ b/web/utils/tooltip-action-utils.js
@@ -10,10 +10,7 @@
ChatMessageInfoItem,
} from 'lib/selectors/chat-selectors.js';
import { useCanEditMessage } from 'lib/shared/edit-messages-utils.js';
-import {
- createMessageReply,
- isInvalidPinSource,
-} from 'lib/shared/message-utils.js';
+import { createMessageReply } from 'lib/shared/message-utils.js';
import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js';
import {
threadHasPermission,
@@ -23,6 +20,7 @@
import { threadPermissions } from 'lib/types/thread-permission-types.js';
import type { ThreadInfo } from 'lib/types/thread-types.js';
import { longAbsoluteDate } from 'lib/utils/date-utils.js';
+import { canToggleMessagePin } from 'lib/utils/toggle-pin-utils.js';
import {
type MessageTooltipAction,
@@ -274,10 +272,7 @@
const { pushModal } = useModalContext();
const { messageInfo, isPinned } = item;
- const canTogglePin =
- !isInvalidPinSource(messageInfo) &&
- threadHasPermission(threadInfo, threadPermissions.MANAGE_PINS) &&
- threadInfo.sourceMessageID !== item.messageInfo.id;
+ const canTogglePin = canToggleMessagePin(messageInfo, threadInfo);
const inputState = React.useContext(InputStateContext);

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 17, 10:52 AM (20 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2518104
Default Alt Text
D9638.id32595.diff (10 KB)

Event Timeline