Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3531908
D9771.id33161.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
42 KB
Referenced Files
None
Subscribers
None
D9771.id33161.diff
View Options
diff --git a/web/account/siwe-login-form.react.js b/web/account/siwe-login-form.react.js
--- a/web/account/siwe-login-form.react.js
+++ b/web/account/siwe-login-form.react.js
@@ -17,7 +17,10 @@
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
import stores from 'lib/facts/stores.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
-import type { LogInStartingPayload } from 'lib/types/account-types.js';
+import type {
+ LogInStartingPayload,
+ LogInExtraInfo,
+} from 'lib/types/account-types.js';
import type {
OLMIdentityKeys,
SignedIdentityKeysBlob,
@@ -92,7 +95,7 @@
useSignedIdentityKeysBlob();
const callSIWEAuthEndpoint = React.useCallback(
- async (message: string, signature: string, extraInfo) => {
+ async (message: string, signature: string, extraInfo: LogInExtraInfo) => {
invariant(
signedIdentityKeysBlob,
'signedIdentityKeysBlob must be set in attemptSIWEAuth',
diff --git a/web/account/traditional-login-form.react.js b/web/account/traditional-login-form.react.js
--- a/web/account/traditional-login-form.react.js
+++ b/web/account/traditional-login-form.react.js
@@ -45,20 +45,26 @@
}, []);
const [username, setUsername] = React.useState<string>('');
- const onUsernameChange = React.useCallback(e => {
- invariant(e.target instanceof HTMLInputElement, 'target not input');
- setUsername(e.target.value);
- }, []);
+ const onUsernameChange = React.useCallback(
+ (e: SyntheticEvent<HTMLInputElement>) => {
+ invariant(e.target instanceof HTMLInputElement, 'target not input');
+ setUsername(e.target.value);
+ },
+ [],
+ );
const onUsernameBlur = React.useCallback(() => {
setUsername(untrimmedUsername => untrimmedUsername.trim());
}, []);
const [password, setPassword] = React.useState<string>('');
- const onPasswordChange = React.useCallback(e => {
- invariant(e.target instanceof HTMLInputElement, 'target not input');
- setPassword(e.target.value);
- }, []);
+ const onPasswordChange = React.useCallback(
+ (e: SyntheticEvent<HTMLInputElement>) => {
+ invariant(e.target instanceof HTMLInputElement, 'target not input');
+ setPassword(e.target.value);
+ },
+ [],
+ );
const [errorMessage, setErrorMessage] = React.useState<string>('');
diff --git a/web/app.react.js b/web/app.react.js
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -165,7 +165,7 @@
});
};
- render() {
+ render(): React.Node {
let content;
if (this.props.loggedIn) {
content = (
@@ -213,10 +213,11 @@
);
}
- onHeaderDoubleClick = () => electron?.doubleClickTopBar();
- stopDoubleClickPropagation = electron ? e => e.stopPropagation() : null;
+ onHeaderDoubleClick = (): void => electron?.doubleClickTopBar();
+ stopDoubleClickPropagation: ?(SyntheticEvent<HTMLAnchorElement>) => void =
+ electron ? e => e.stopPropagation() : null;
- renderLoginPage() {
+ renderLoginPage(): React.Node {
const { loginMethod } = this.props.navInfo;
if (loginMethod === 'qr-code') {
@@ -226,7 +227,7 @@
return <Splash />;
}
- renderMainContent() {
+ renderMainContent(): React.Node {
const mainContent = this.getMainContentWithSwitcher();
let navigationArrows = null;
@@ -284,7 +285,7 @@
);
}
- getMainContentWithSwitcher() {
+ getMainContentWithSwitcher(): React.Node {
const { tab, settingsSection } = this.props.navInfo;
let mainContent;
diff --git a/web/avatars/avatar-hooks.react.js b/web/avatars/avatar-hooks.react.js
--- a/web/avatars/avatar-hooks.react.js
+++ b/web/avatars/avatar-hooks.react.js
@@ -21,7 +21,7 @@
const callUploadMultimedia = useServerCall(uploadMultimedia);
const callBlobServiceUpload = useBlobServiceUpload();
const uploadAvatarMedia = React.useCallback(
- async file => {
+ async (file: File): Promise<UpdateUserAvatarRequest> => {
const validatedFile = await validateFile(file);
const { result } = validatedFile;
if (!result.success) {
diff --git a/web/avatars/edit-thread-avatar-menu.react.js b/web/avatars/edit-thread-avatar-menu.react.js
--- a/web/avatars/edit-thread-avatar-menu.react.js
+++ b/web/avatars/edit-thread-avatar-menu.react.js
@@ -57,8 +57,10 @@
const uploadAvatarMedia = useUploadAvatarMedia();
const onImageSelected = React.useCallback(
- async event => {
- const uploadResult = await uploadAvatarMedia(event.target.files[0]);
+ async (event: SyntheticEvent<HTMLInputElement>) => {
+ const { target } = event;
+ invariant(target instanceof HTMLInputElement, 'target not input');
+ const uploadResult = await uploadAvatarMedia(target.files[0]);
baseSetThreadAvatar(threadInfo.id, uploadResult);
},
[baseSetThreadAvatar, threadInfo.id, uploadAvatarMedia],
diff --git a/web/avatars/edit-user-avatar-menu.react.js b/web/avatars/edit-user-avatar-menu.react.js
--- a/web/avatars/edit-user-avatar-menu.react.js
+++ b/web/avatars/edit-user-avatar-menu.react.js
@@ -69,8 +69,10 @@
const uploadAvatarMedia = useUploadAvatarMedia();
const onImageSelected = React.useCallback(
- async event => {
- const uploadResult = await uploadAvatarMedia(event.target.files[0]);
+ async (event: SyntheticEvent<HTMLInputElement>) => {
+ const { target } = event;
+ invariant(target instanceof HTMLInputElement, 'target not input');
+ const uploadResult = await uploadAvatarMedia(target.files[0]);
baseSetUserAvatar(uploadResult);
},
[baseSetUserAvatar, uploadAvatarMedia],
diff --git a/web/avatars/emoji-avatar-selection-modal.react.js b/web/avatars/emoji-avatar-selection-modal.react.js
--- a/web/avatars/emoji-avatar-selection-modal.react.js
+++ b/web/avatars/emoji-avatar-selection-modal.react.js
@@ -53,10 +53,13 @@
[pendingAvatarColor, pendingAvatarEmoji],
);
- const onEmojiSelect = React.useCallback(selection => {
- setUpdateAvatarStatus();
- setPendingAvatarEmoji(selection.native);
- }, []);
+ const onEmojiSelect = React.useCallback(
+ (selection: { +native: string, ... }) => {
+ setUpdateAvatarStatus();
+ setPendingAvatarEmoji(selection.native);
+ },
+ [],
+ );
const onColorSelection = React.useCallback((hex: string) => {
setUpdateAvatarStatus();
diff --git a/web/calendar/calendar.react.js b/web/calendar/calendar.react.js
--- a/web/calendar/calendar.react.js
+++ b/web/calendar/calendar.react.js
@@ -41,6 +41,11 @@
import type { NavInfo } from '../types/nav-types.js';
import { canonicalURLFromReduxState } from '../url-utils.js';
+type StartAndEndDates = {
+ +startDate: string,
+ +endDate: string,
+};
+
type BaseProps = {
+url: string,
};
@@ -69,7 +74,7 @@
dayOfMonth: number,
monthInput: ?number = undefined,
yearInput: ?number = undefined,
- ) {
+ ): Date {
return getDate(
yearInput ? yearInput : this.props.year,
monthInput ? monthInput : this.props.month,
@@ -77,7 +82,7 @@
);
}
- prevMonthDates() {
+ prevMonthDates(): StartAndEndDates {
const { year, month } = this.props;
const lastMonthDate = getDate(year, month - 1, 1);
const prevYear = lastMonthDate.getFullYear();
@@ -88,7 +93,7 @@
};
}
- nextMonthDates() {
+ nextMonthDates(): StartAndEndDates {
const { year, month } = this.props;
const nextMonthDate = getDate(year, month + 1, 1);
const nextYear = nextMonthDate.getFullYear();
@@ -99,7 +104,7 @@
};
}
- render() {
+ render(): React.Node {
const { year, month } = this.props;
const monthName = dateFormat(getDate(year, month, 1), 'mmmm');
const prevURL = canonicalURLFromReduxState(
diff --git a/web/calendar/day.react.js b/web/calendar/day.react.js
--- a/web/calendar/day.react.js
+++ b/web/calendar/day.react.js
@@ -65,7 +65,7 @@
}
}
- render() {
+ render(): React.Node {
const now = new Date();
const isToday = dateString(now) === this.props.dayString;
const tdClasses = classNames(css.day, { [css.currentDay]: isToday });
diff --git a/web/calendar/filter-panel.react.js b/web/calendar/filter-panel.react.js
--- a/web/calendar/filter-panel.react.js
+++ b/web/calendar/filter-panel.react.js
@@ -77,7 +77,7 @@
return this.props.filteredCommunityThreadIDs.has(threadID);
}
- render() {
+ render(): React.Node {
const filterThreadInfos = this.state.query
? this.state.searchResults
: this.props.filterThreadInfos;
@@ -275,7 +275,7 @@
+selected: boolean,
};
class Item extends React.PureComponent<ItemProps> {
- render() {
+ render(): React.Node {
const threadInfo = this.props.filterThreadInfo.threadInfo;
const beforeCheckStyles = { borderColor: `#${threadInfo.color}` };
let afterCheck = null;
@@ -343,7 +343,7 @@
+selected: boolean,
};
class Category extends React.PureComponent<CategoryProps> {
- render() {
+ render(): React.Node {
const beforeCheckStyles = { borderColor: 'white' };
let afterCheck = null;
if (this.props.selected) {
diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js
--- a/web/chat/chat-input-bar.react.js
+++ b/web/chat/chat-input-bar.react.js
@@ -166,7 +166,7 @@
static unassignedUploadIDs(
pendingUploads: $ReadOnlyArray<PendingMultimediaUpload>,
- ) {
+ ): Array<string> {
return pendingUploads
.filter(
(pendingUpload: PendingMultimediaUpload) => !pendingUpload.messageID,
@@ -199,7 +199,7 @@
this.props.inputState.removeReplyListener(this.focusAndUpdateText);
}
- render() {
+ render(): React.Node {
const isMember = viewerIsMember(this.props.threadInfo);
const canJoin = threadHasPermission(
this.props.threadInfo,
@@ -540,7 +540,7 @@
this.props.dispatchActionPromise(joinThreadActionTypes, this.joinAction());
};
- async joinAction() {
+ async joinAction(): Promise<ThreadJoinPayload> {
const query = this.props.calendarQuery();
return await this.props.joinThread({
threadID: this.props.threadInfo.id,
diff --git a/web/chat/chat-message-list.react.js b/web/chat/chat-message-list.react.js
--- a/web/chat/chat-message-list.react.js
+++ b/web/chat/chat-message-list.react.js
@@ -107,7 +107,7 @@
this.props.removeScrollToMessageListener(this.scrollToMessage);
}
- getSnapshotBeforeUpdate(prevProps: Props) {
+ getSnapshotBeforeUpdate(prevProps: Props): ?Snapshot {
if (
ChatMessageList.hasNewMessage(this.props, prevProps) &&
this.messageContainer
@@ -118,7 +118,7 @@
return null;
}
- static hasNewMessage(props: Props, prevProps: Props) {
+ static hasNewMessage(props: Props, prevProps: Props): boolean {
const { messageListData } = props;
if (!messageListData || messageListData.length === 0) {
return false;
@@ -133,7 +133,7 @@
);
}
- componentDidUpdate(prevProps: Props, prevState, snapshot: ?Snapshot) {
+ componentDidUpdate(prevProps: Props, prevState: State, snapshot: ?Snapshot) {
const { messageListData } = this.props;
const prevMessageListData = prevProps.messageListData;
@@ -180,14 +180,14 @@
}
}
- static keyExtractor(item: ChatMessageItem) {
+ static keyExtractor(item: ChatMessageItem): string {
if (item.itemType === 'loader') {
return 'loader';
}
return messageKey(item.messageInfo);
}
- renderItem = item => {
+ renderItem = (item: ChatMessageItem): React.Node => {
if (item.itemType === 'loader') {
return (
<div key="loader" className={css.loading}>
@@ -271,7 +271,7 @@
return maxHeight;
};
- willMessageEditWindowOverflow(composedMessageID: string) {
+ willMessageEditWindowOverflow(composedMessageID: string): boolean {
const { messageContainer } = this;
if (!messageContainer) {
return false;
@@ -305,7 +305,7 @@
return messageBottom > containerBottom || messageTop < containerTop;
}
- render() {
+ render(): React.Node {
const { messageListData, threadInfo, inputState, isEditState } = this.props;
if (!messageListData) {
return <div className={css.container} />;
@@ -353,7 +353,7 @@
this.debounceEditModeAfterScrollToMessage();
};
- debounceEditModeAfterScrollToMessage = _debounce(() => {
+ debounceEditModeAfterScrollToMessage: () => void = _debounce(() => {
if (this.state.scrollingEndCallback) {
this.state.scrollingEndCallback();
}
diff --git a/web/chat/chat-thread-list-item-menu.react.js b/web/chat/chat-thread-list-item-menu.react.js
--- a/web/chat/chat-thread-list-item-menu.react.js
+++ b/web/chat/chat-thread-list-item-menu.react.js
@@ -21,7 +21,7 @@
const active = useThreadIsActive(threadInfo.id);
const [menuVisible, setMenuVisible] = React.useState(false);
const toggleMenu = React.useCallback(
- event => {
+ (event: SyntheticEvent<HTMLButtonElement>) => {
event.stopPropagation();
setMenuVisible(!menuVisible);
},
@@ -39,7 +39,7 @@
);
const onToggleUnreadStatusClicked = React.useCallback(
- event => {
+ (event: SyntheticEvent<HTMLButtonElement>) => {
event.stopPropagation();
toggleUnreadStatus();
},
diff --git a/web/chat/chat-thread-list.react.js b/web/chat/chat-thread-list.react.js
--- a/web/chat/chat-thread-list.react.js
+++ b/web/chat/chat-thread-list.react.js
@@ -41,7 +41,12 @@
}
};
-const renderItem = ({ index, data, style }) => {
+type RenderItemInput = {
+ +index: number,
+ +data: $ReadOnlyArray<Item>,
+ +style: CSSStyleDeclaration,
+};
+const renderItem: RenderItemInput => React.Node = ({ index, data, style }) => {
let item;
if (data[index].type === 'search') {
item = <ChatThreadListSearch />;
@@ -129,7 +134,7 @@
items.push({ type: 'empty' });
}
- const itemSize = index => {
+ const itemSize = (index: number) => {
if (items[index].type === 'search') {
return sizes.search;
} else if (items[index].type === 'empty') {
diff --git a/web/chat/edit-text-message.react.js b/web/chat/edit-text-message.react.js
--- a/web/chat/edit-text-message.react.js
+++ b/web/chat/edit-text-message.react.js
@@ -98,7 +98,7 @@
}, [background, updatePosition]);
const preventCloseTab = React.useCallback(
- event => {
+ (event: BeforeUnloadEvent) => {
if (!isMessageEdited) {
return null;
}
diff --git a/web/chat/failed-send.react.js b/web/chat/failed-send.react.js
--- a/web/chat/failed-send.react.js
+++ b/web/chat/failed-send.react.js
@@ -79,7 +79,7 @@
}
}
- render() {
+ render(): React.Node {
return (
<div className={css.failedSend}>
<span className={css.deliveryFailed}>Delivery failed.</span>
diff --git a/web/chat/message-tooltip.react.js b/web/chat/message-tooltip.react.js
--- a/web/chat/message-tooltip.react.js
+++ b/web/chat/message-tooltip.react.js
@@ -179,7 +179,7 @@
);
const onEmojiSelect = React.useCallback(
- emoji => {
+ (emoji: { +native: string, ... }) => {
const reactionInput = emoji.native;
sendReaction(reactionInput);
},
diff --git a/web/chat/multimedia-message.react.js b/web/chat/multimedia-message.react.js
--- a/web/chat/multimedia-message.react.js
+++ b/web/chat/multimedia-message.react.js
@@ -27,7 +27,7 @@
+inputState: ?InputState,
};
class MultimediaMessage extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const { item, inputState } = this.props;
invariant(
item.messageInfo.type === messageTypes.IMAGES ||
diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js
--- a/web/chat/robotext-message.react.js
+++ b/web/chat/robotext-message.react.js
@@ -108,7 +108,7 @@
+dispatch: Dispatch,
};
class InnerThreadEntity extends React.PureComponent<InnerThreadEntityProps> {
- render() {
+ render(): React.Node {
return <a onClick={this.onClickThread}>{this.props.name}</a>;
}
diff --git a/web/components/button.react.js b/web/components/button.react.js
--- a/web/components/button.react.js
+++ b/web/components/button.react.js
@@ -61,7 +61,7 @@
style = buttonThemes.standard;
}
- const wrappedChildren = React.Children.map(children, child => {
+ const wrappedChildren = React.Children.map(children, (child: React.Node) => {
if (typeof child === 'string' || typeof child === 'number') {
return <span>{child}</span>;
}
diff --git a/web/components/dropdown.react.js b/web/components/dropdown.react.js
--- a/web/components/dropdown.react.js
+++ b/web/components/dropdown.react.js
@@ -48,7 +48,7 @@
}, [disabled, isOpen]);
const handleSelection = React.useCallback(
- selection => {
+ (selection: DropdownOption) => {
setActiveSelection(selection.id);
setIsOpen(false);
},
diff --git a/web/components/menu.react.js b/web/components/menu.react.js
--- a/web/components/menu.react.js
+++ b/web/components/menu.react.js
@@ -102,7 +102,7 @@
}, [closeMenu]);
const onClickMenuCallback = React.useCallback(
- e => {
+ (e: SyntheticEvent<HTMLButtonElement>) => {
e.stopPropagation();
setCurrentOpenMenu(ourSymbol.current);
},
diff --git a/web/components/navigation-arrows.react.js b/web/components/navigation-arrows.react.js
--- a/web/components/navigation-arrows.react.js
+++ b/web/components/navigation-arrows.react.js
@@ -9,7 +9,8 @@
import electron from '../electron.js';
import history from '../router-history.js';
-const stopDoubleClickPropagation = e => e.stopPropagation();
+const stopDoubleClickPropagation = (e: SyntheticEvent<HTMLAnchorElement>) =>
+ e.stopPropagation();
function NavigationArrows(): React.Node {
const goBack = React.useCallback(
diff --git a/web/components/search.react.js b/web/components/search.react.js
--- a/web/components/search.react.js
+++ b/web/components/search.react.js
@@ -1,5 +1,6 @@
// @flow
+import invariant from 'invariant';
import * as React from 'react';
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
@@ -30,8 +31,10 @@
}, [onChangeText, onClearText]);
const onChange = React.useCallback(
- event => {
- onChangeText(event.target.value);
+ (event: SyntheticEvent<HTMLInputElement>) => {
+ const { target } = event;
+ invariant(target instanceof HTMLInputElement, 'target not input');
+ onChangeText(target.value);
},
[onChangeText],
);
diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js
--- a/web/input/input-state-container.react.js
+++ b/web/input/input-state-container.react.js
@@ -100,6 +100,9 @@
type PendingMultimediaUpload,
type TypeaheadState,
InputStateContext,
+ type BaseInputState,
+ type TypeaheadInputState,
+ type InputState,
} from './input-state.js';
import { encryptFile } from '../media/encryption-utils.js';
import { generateThumbHash } from '../media/image-utils.js';
@@ -172,7 +175,10 @@
},
};
replyCallbacks: Array<(message: string) => void> = [];
- pendingThreadCreations = new Map<string, Promise<string>>();
+ pendingThreadCreations: Map<string, Promise<string>> = new Map<
+ string,
+ Promise<string>,
+ >();
// TODO: flip the switch
// Note that this enables Blob service for encrypted media only
useBlobServiceUploads = false;
@@ -181,7 +187,7 @@
// sidebar, the sidebar gets created right away, but the message needs to wait
// for the uploads to complete before sending. We use this Set to track the
// message localIDs that need sidebarCreation: true.
- pendingSidebarCreationMessageLocalIDs = new Set<string>();
+ pendingSidebarCreationMessageLocalIDs: Set<string> = new Set<string>();
static reassignToRealizedThreads<T>(
state: { +[threadID: string]: T },
@@ -200,7 +206,7 @@
return updated ? newState : null;
}
- static getDerivedStateFromProps(props: Props, state: State) {
+ static getDerivedStateFromProps(props: Props, state: State): ?Partial<State> {
const pendingUploads = InputStateContainer.reassignToRealizedThreads(
state.pendingUploads,
props,
@@ -224,7 +230,7 @@
return stateUpdate;
}
- static completedMessageIDs(state: State) {
+ static completedMessageIDs(state: State): Set<string> {
const completed = new Map();
for (const threadID in state.pendingUploads) {
const pendingUploads = state.pendingUploads[threadID];
@@ -404,7 +410,9 @@
return threadInfoInsideCommunity(threadInfo, commStaffCommunity.id);
}
- async sendMultimediaMessage(messageInfo: RawMultimediaMessageInfo) {
+ async sendMultimediaMessage(
+ messageInfo: RawMultimediaMessageInfo,
+ ): Promise<void> {
if (!threadIsPending(messageInfo.threadID)) {
this.props.dispatchActionPromise(
sendMultimediaMessageActionTypes,
@@ -564,74 +572,84 @@
return threadCreationPromise;
}
- inputBaseStateSelector = _memoize((threadID: ?string) =>
- createSelector(
- (propsAndState: PropsAndState) =>
- threadID ? propsAndState.pendingUploads[threadID] : null,
- (propsAndState: PropsAndState) =>
- threadID ? propsAndState.drafts[draftKeyFromThreadID(threadID)] : null,
- (propsAndState: PropsAndState) =>
- threadID ? propsAndState.textCursorPositions[threadID] : null,
- (
- pendingUploads: ?{ [localUploadID: string]: PendingMultimediaUpload },
- draft: ?string,
- textCursorPosition: ?number,
- ) => {
- let threadPendingUploads = [];
- const assignedUploads = {};
- if (pendingUploads) {
- const [uploadsWithMessageIDs, uploadsWithoutMessageIDs] =
- _partition('messageID')(pendingUploads);
- threadPendingUploads = _sortBy('localID')(uploadsWithoutMessageIDs);
- const threadAssignedUploads = _groupBy('messageID')(
- uploadsWithMessageIDs,
- );
- for (const messageID in threadAssignedUploads) {
- // lodash libdefs don't return $ReadOnlyArray
- assignedUploads[messageID] = [...threadAssignedUploads[messageID]];
+ inputBaseStateSelector: (?string) => PropsAndState => BaseInputState =
+ _memoize((threadID: ?string) =>
+ createSelector(
+ (propsAndState: PropsAndState) =>
+ threadID ? propsAndState.pendingUploads[threadID] : null,
+ (propsAndState: PropsAndState) =>
+ threadID
+ ? propsAndState.drafts[draftKeyFromThreadID(threadID)]
+ : null,
+ (propsAndState: PropsAndState) =>
+ threadID ? propsAndState.textCursorPositions[threadID] : null,
+ (
+ pendingUploads: ?{ [localUploadID: string]: PendingMultimediaUpload },
+ draft: ?string,
+ textCursorPosition: ?number,
+ ) => {
+ let threadPendingUploads = [];
+ const assignedUploads = {};
+ if (pendingUploads) {
+ const [uploadsWithMessageIDs, uploadsWithoutMessageIDs] =
+ _partition('messageID')(pendingUploads);
+ threadPendingUploads = _sortBy('localID')(uploadsWithoutMessageIDs);
+ const threadAssignedUploads = _groupBy('messageID')(
+ uploadsWithMessageIDs,
+ );
+ for (const messageID in threadAssignedUploads) {
+ // lodash libdefs don't return $ReadOnlyArray
+ assignedUploads[messageID] = [
+ ...threadAssignedUploads[messageID],
+ ];
+ }
}
- }
- return {
- pendingUploads: threadPendingUploads,
- assignedUploads,
- draft: draft ?? '',
- textCursorPosition: textCursorPosition ?? 0,
- appendFiles: (threadInfo: ThreadInfo, files: $ReadOnlyArray<File>) =>
- this.appendFiles(threadInfo, files),
- cancelPendingUpload: (localUploadID: string) =>
- this.cancelPendingUpload(threadID, localUploadID),
- sendTextMessage: (
- messageInfo: RawTextMessageInfo,
- threadInfo: ThreadInfo,
- parentThreadInfo: ?ThreadInfo,
- ) => this.sendTextMessage(messageInfo, threadInfo, parentThreadInfo),
- createMultimediaMessage: (localID: number, threadInfo: ThreadInfo) =>
- this.createMultimediaMessage(localID, threadInfo),
- setDraft: (newDraft: string) => this.setDraft(threadID, newDraft),
- setTextCursorPosition: (newPosition: number) =>
- this.setTextCursorPosition(threadID, newPosition),
- messageHasUploadFailure: (localMessageID: string) =>
- this.messageHasUploadFailure(assignedUploads[localMessageID]),
- retryMultimediaMessage: (
- localMessageID: string,
- threadInfo: ThreadInfo,
- ) =>
- this.retryMultimediaMessage(
- localMessageID,
- threadInfo,
- assignedUploads[localMessageID],
- ),
- addReply: (message: string) => this.addReply(message),
- addReplyListener: this.addReplyListener,
- removeReplyListener: this.removeReplyListener,
- registerSendCallback: this.props.registerSendCallback,
- unregisterSendCallback: this.props.unregisterSendCallback,
- };
- },
- ),
- );
+ return {
+ pendingUploads: threadPendingUploads,
+ assignedUploads,
+ draft: draft ?? '',
+ textCursorPosition: textCursorPosition ?? 0,
+ appendFiles: (
+ threadInfo: ThreadInfo,
+ files: $ReadOnlyArray<File>,
+ ) => this.appendFiles(threadInfo, files),
+ cancelPendingUpload: (localUploadID: string) =>
+ this.cancelPendingUpload(threadID, localUploadID),
+ sendTextMessage: (
+ messageInfo: RawTextMessageInfo,
+ threadInfo: ThreadInfo,
+ parentThreadInfo: ?ThreadInfo,
+ ) =>
+ this.sendTextMessage(messageInfo, threadInfo, parentThreadInfo),
+ createMultimediaMessage: (
+ localID: number,
+ threadInfo: ThreadInfo,
+ ) => this.createMultimediaMessage(localID, threadInfo),
+ setDraft: (newDraft: string) => this.setDraft(threadID, newDraft),
+ setTextCursorPosition: (newPosition: number) =>
+ this.setTextCursorPosition(threadID, newPosition),
+ messageHasUploadFailure: (localMessageID: string) =>
+ this.messageHasUploadFailure(assignedUploads[localMessageID]),
+ retryMultimediaMessage: (
+ localMessageID: string,
+ threadInfo: ThreadInfo,
+ ) =>
+ this.retryMultimediaMessage(
+ localMessageID,
+ threadInfo,
+ assignedUploads[localMessageID],
+ ),
+ addReply: (message: string) => this.addReply(message),
+ addReplyListener: this.addReplyListener,
+ removeReplyListener: this.removeReplyListener,
+ registerSendCallback: this.props.registerSendCallback,
+ unregisterSendCallback: this.props.unregisterSendCallback,
+ };
+ },
+ ),
+ );
- typeaheadStateSelector = createSelector(
+ typeaheadStateSelector: PropsAndState => TypeaheadInputState = createSelector(
(propsAndState: PropsAndState) => propsAndState.typeaheadState,
(typeaheadState: TypeaheadState) => ({
typeaheadState,
@@ -639,7 +657,10 @@
}),
);
- inputStateSelector = createSelector(
+ inputStateSelector: ({
+ +inputBaseState: BaseInputState,
+ +typeaheadState: TypeaheadInputState,
+ }) => InputState = createSelector(
state => state.inputBaseState,
state => state.typeaheadState,
(inputBaseState, typeaheadState) => ({
@@ -816,7 +837,7 @@
uploadFiles(
threadID: string,
uploads: $ReadOnlyArray<PendingMultimediaUpload>,
- ) {
+ ): Promise<mixed> {
return Promise.all(
uploads.map(upload => this.uploadFile(threadID, upload)),
);
@@ -1450,7 +1471,7 @@
messageHasUploadFailure(
pendingUploads: ?$ReadOnlyArray<PendingMultimediaUpload>,
- ) {
+ ): boolean {
if (!pendingUploads) {
return false;
}
@@ -1566,7 +1587,7 @@
);
};
- render() {
+ render(): React.Node {
const { activeChatThreadID } = this.props;
// we're going with two selectors as we want to avoid
diff --git a/web/input/input-state.js b/web/input/input-state.js
--- a/web/input/input-state.js
+++ b/web/input/input-state.js
@@ -55,15 +55,13 @@
+accept: ?() => void,
};
-// This type represents the input state for a particular thread
-export type InputState = {
+export type BaseInputState = {
+pendingUploads: $ReadOnlyArray<PendingMultimediaUpload>,
+assignedUploads: {
[messageID: string]: $ReadOnlyArray<PendingMultimediaUpload>,
},
+draft: string,
+textCursorPosition: number,
- +typeaheadState: TypeaheadState,
+appendFiles: (
threadInfo: ThreadInfo,
files: $ReadOnlyArray<File>,
@@ -77,7 +75,6 @@
+createMultimediaMessage: (localID: number, threadInfo: ThreadInfo) => void,
+setDraft: (draft: string) => void,
+setTextCursorPosition: (newPosition: number) => void,
- +setTypeaheadState: ($Shape<TypeaheadState>) => void,
+messageHasUploadFailure: (localMessageID: string) => boolean,
+retryMultimediaMessage: (
localMessageID: string,
@@ -90,6 +87,17 @@
+unregisterSendCallback: (() => mixed) => void,
};
+export type TypeaheadInputState = {
+ +typeaheadState: TypeaheadState,
+ +setTypeaheadState: ($Shape<TypeaheadState>) => void,
+};
+
+// This type represents the input state for a particular thread
+export type InputState = {
+ ...BaseInputState,
+ ...TypeaheadInputState,
+};
+
const InputStateContext: React.Context<?InputState> =
React.createContext<?InputState>(null);
diff --git a/web/modals/history/history-entry.react.js b/web/modals/history/history-entry.react.js
--- a/web/modals/history/history-entry.react.js
+++ b/web/modals/history/history-entry.react.js
@@ -17,6 +17,7 @@
type RestoreEntryInfo,
type RestoreEntryResult,
type CalendarQuery,
+ type RestoreEntryPayload,
} from 'lib/types/entry-types.js';
import type { LoadingStatus } from 'lib/types/loading-types.js';
import type { ResolvedThreadInfo } from 'lib/types/thread-types.js';
@@ -49,7 +50,7 @@
};
class HistoryEntry extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
let deleted = null;
if (this.props.entryInfo.deleted) {
let restore = null;
@@ -133,7 +134,7 @@
this.props.onClick(entryID);
};
- async restoreEntryAction() {
+ async restoreEntryAction(): Promise<RestoreEntryPayload> {
const entryID = this.props.entryInfo.id;
invariant(entryID, 'entry should have ID');
const result = await this.props.restoreEntry({
diff --git a/web/modals/history/history-modal.react.js b/web/modals/history/history-modal.react.js
--- a/web/modals/history/history-modal.react.js
+++ b/web/modals/history/history-modal.react.js
@@ -71,7 +71,7 @@
+revisions: $ReadOnlyArray<HistoryRevisionInfo>,
};
class HistoryModal extends React.PureComponent<Props, State> {
- static defaultProps = { currentEntryID: null };
+ static defaultProps: Partial<Props> = { currentEntryID: null };
constructor(props: Props) {
super(props);
@@ -91,7 +91,7 @@
}
}
- render() {
+ render(): React.Node {
let allHistoryButton = null;
if (this.state.mode === 'entry') {
allHistoryButton = (
diff --git a/web/modals/search/message-search-modal.react.js b/web/modals/search/message-search-modal.react.js
--- a/web/modals/search/message-search-modal.react.js
+++ b/web/modals/search/message-search-modal.react.js
@@ -3,6 +3,7 @@
import * as React from 'react';
import { useModalContext } from 'lib/components/modal-provider.react.js';
+import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
import type { ThreadInfo } from 'lib/types/thread-types.js';
import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js';
@@ -40,7 +41,7 @@
}, [setQuery, input, searchMessages, threadInfo.id]);
const onKeyDown = React.useCallback(
- event => {
+ (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') {
onPressSearch();
}
@@ -76,7 +77,7 @@
}, [clearTooltip, possiblyLoadMoreMessages]);
const renderItem = React.useCallback(
- item => (
+ (item: ChatMessageInfoItem) => (
<MessageResult
key={item.messageInfo.id}
item={item}
diff --git a/web/modals/threads/gallery/thread-settings-media-gallery.react.js b/web/modals/threads/gallery/thread-settings-media-gallery.react.js
--- a/web/modals/threads/gallery/thread-settings-media-gallery.react.js
+++ b/web/modals/threads/gallery/thread-settings-media-gallery.react.js
@@ -1,5 +1,6 @@
// @flow
+import invariant from 'invariant';
import * as React from 'react';
import { useFetchThreadMedia } from 'lib/actions/thread-actions.js';
@@ -142,8 +143,9 @@
}, [tab, mediaInfos, onClick]);
const handleScroll = React.useCallback(
- async event => {
+ async (event: SyntheticEvent<HTMLDivElement>) => {
const container = event.target;
+ invariant(container instanceof HTMLDivElement, 'target not div');
// Load more data when the user is within 1000 pixels of the end
const buffer = 1000;
diff --git a/web/modals/threads/members/add-members-modal.react.js b/web/modals/threads/members/add-members-modal.react.js
--- a/web/modals/threads/members/add-members-modal.react.js
+++ b/web/modals/threads/members/add-members-modal.react.js
@@ -78,7 +78,7 @@
const userSearchResultsWithENSNames = useENSNames(userSearchResults);
const onSwitchUser = React.useCallback(
- userID =>
+ (userID: string) =>
setPendingUsersToAdd(users => {
const newUsers = new Set(users);
if (newUsers.has(userID)) {
diff --git a/web/modals/threads/members/member.react.js b/web/modals/threads/members/member.react.js
--- a/web/modals/threads/members/member.react.js
+++ b/web/modals/threads/members/member.react.js
@@ -44,7 +44,7 @@
const roleName = roles.get(memberInfo.id)?.name;
const onMenuChange = React.useCallback(
- menuOpen => {
+ (menuOpen: boolean) => {
if (menuOpen) {
setOpenMenu(() => memberInfo.id);
} else {
diff --git a/web/modals/threads/sidebars/sidebar.react.js b/web/modals/threads/sidebars/sidebar.react.js
--- a/web/modals/threads/sidebars/sidebar.react.js
+++ b/web/modals/threads/sidebars/sidebar.react.js
@@ -31,7 +31,7 @@
const navigateToThread = useOnClickThread(threadInfo);
const onClickThread = React.useCallback(
- event => {
+ (event: SyntheticEvent<HTMLButtonElement>) => {
popModal();
navigateToThread(event);
},
diff --git a/web/modals/threads/subchannels/subchannel.react.js b/web/modals/threads/subchannels/subchannel.react.js
--- a/web/modals/threads/subchannels/subchannel.react.js
+++ b/web/modals/threads/subchannels/subchannel.react.js
@@ -40,7 +40,7 @@
const navigateToThread = useOnClickThread(threadInfo);
const onClickThread = React.useCallback(
- event => {
+ (event: SyntheticEvent<HTMLButtonElement>) => {
popModal();
navigateToThread(event);
},
diff --git a/web/modals/update-modal.react.js b/web/modals/update-modal.react.js
--- a/web/modals/update-modal.react.js
+++ b/web/modals/update-modal.react.js
@@ -73,7 +73,7 @@
React.useEffect(
() =>
- electron?.onNewVersionAvailable?.(version => {
+ electron?.onNewVersionAvailable?.((version: string) => {
// On these versions we want to update immediately because there's
// an issue if the user decides to update 10min after showing the modal
if (electron?.version === '1.0.0' || electron?.version === '2.0.0') {
diff --git a/web/push-notif/push-notifs-handler.js b/web/push-notif/push-notifs-handler.js
--- a/web/push-notif/push-notifs-handler.js
+++ b/web/push-notif/push-notifs-handler.js
@@ -28,7 +28,7 @@
React.useEffect(
() =>
- electron?.onDeviceTokenRegistered?.(token => {
+ electron?.onDeviceTokenRegistered?.((token: ?string) => {
dispatchActionPromise(
setDeviceTokenActionTypes,
callSetDeviceToken(token),
@@ -41,20 +41,22 @@
React.useEffect(
() =>
- electron?.onNotificationClicked?.(({ threadID }) => {
- const convertedThreadID = convertNonPendingIDToNewSchema(
- threadID,
- ashoatKeyserverID,
- );
-
- const payload = {
- chatMode: 'view',
- activeChatThreadID: convertedThreadID,
- tab: 'chat',
- };
-
- dispatch({ type: updateNavInfoActionType, payload });
- }),
+ electron?.onNotificationClicked?.(
+ ({ threadID }: { +threadID: string }) => {
+ const convertedThreadID = convertNonPendingIDToNewSchema(
+ threadID,
+ ashoatKeyserverID,
+ );
+
+ const payload = {
+ chatMode: 'view',
+ activeChatThreadID: convertedThreadID,
+ tab: 'chat',
+ };
+
+ dispatch({ type: updateNavInfoActionType, payload });
+ },
+ ),
[dispatch],
);
}
diff --git a/web/redux/focus-handler.react.js b/web/redux/focus-handler.react.js
--- a/web/redux/focus-handler.react.js
+++ b/web/redux/focus-handler.react.js
@@ -35,7 +35,7 @@
const dispatch = useDispatch();
const curWindowActive = useSelector(state => state.windowActive);
const updateRedux = React.useCallback(
- windowActive => {
+ (windowActive: boolean) => {
if (windowActive === curWindowActive) {
return;
}
diff --git a/web/redux/initial-state-gate.js b/web/redux/initial-state-gate.js
--- a/web/redux/initial-state-gate.js
+++ b/web/redux/initial-state-gate.js
@@ -61,7 +61,7 @@
const childFunction = React.useCallback(
// This argument is passed from `PersistGate`. It means that the state is
// rehydrated and we can start fetching the initial info.
- bootstrapped => {
+ (bootstrapped: boolean) => {
if (bootstrapped && initialStateLoaded) {
return children;
} else {
diff --git a/web/redux/persist.js b/web/redux/persist.js
--- a/web/redux/persist.js
+++ b/web/redux/persist.js
@@ -41,7 +41,7 @@
declare var keyserverURL: string;
const migrations = {
- [1]: async state => {
+ [1]: async (state: any) => {
const {
primaryIdentityPublicKey,
...stateWithoutPrimaryIdentityPublicKey
@@ -56,7 +56,7 @@
},
};
},
- [2]: async state => {
+ [2]: async (state: AppState) => {
return state;
},
[3]: async (state: AppState) => {
@@ -90,7 +90,7 @@
return newState;
},
- [4]: async state => {
+ [4]: async (state: any) => {
const { lastCommunicatedPlatformDetails, keyserverStore, ...rest } = state;
return {
@@ -107,7 +107,7 @@
},
};
},
- [5]: async state => {
+ [5]: async (state: any) => {
const databaseModule = await getDatabaseModule();
const isDatabaseSupported = await databaseModule.isDatabaseSupported();
if (!isDatabaseSupported) {
@@ -135,7 +135,7 @@
return state;
},
- [6]: async state => ({
+ [6]: async (state: AppState) => ({
...state,
integrityStore: { threadHashes: {}, threadHashingStatus: 'starting' },
}),
@@ -166,11 +166,11 @@
},
};
},
- [8]: async state => ({
+ [8]: async (state: AppState) => ({
...state,
globalThemeInfo: defaultGlobalThemeInfo,
}),
- [9]: async state => ({
+ [9]: async (state: AppState) => ({
...state,
keyserverStore: {
...state.keyserverStore,
@@ -183,7 +183,7 @@
},
},
}),
- [10]: async state => {
+ [10]: async (state: AppState) => {
const { keyserverInfos } = state.keyserverStore;
const newKeyserverInfos = {};
for (const key in keyserverInfos) {
diff --git a/web/redux/visibility-handler.react.js b/web/redux/visibility-handler.react.js
--- a/web/redux/visibility-handler.react.js
+++ b/web/redux/visibility-handler.react.js
@@ -11,9 +11,12 @@
function VisibilityHandler(): React.Node {
const visibility = useVisibility();
const [visible, setVisible] = React.useState(!visibility.hidden());
- const onVisibilityChange = React.useCallback((event, state: string) => {
- setVisible(state === 'visible');
- }, []);
+ const onVisibilityChange = React.useCallback(
+ (event: mixed, state: string) => {
+ setVisible(state === 'visible');
+ },
+ [],
+ );
React.useEffect(() => {
const listener = visibility.change(onVisibilityChange);
return () => {
@@ -24,7 +27,7 @@
const dispatch = useDispatch();
const curForeground = useIsAppForegrounded();
const updateRedux = React.useCallback(
- foreground => {
+ (foreground: boolean) => {
if (foreground === curForeground) {
return;
}
diff --git a/web/settings/password-change-modal.js b/web/settings/password-change-modal.js
--- a/web/settings/password-change-modal.js
+++ b/web/settings/password-change-modal.js
@@ -56,7 +56,7 @@
this.newPasswordInput.focus();
}
- render() {
+ render(): React.Node {
let errorMsg;
if (this.state.errorMessage) {
errorMsg = (
@@ -188,7 +188,7 @@
);
};
- async changeUserSettingsAction() {
+ async changeUserSettingsAction(): Promise<void> {
try {
await this.props.changeUserPassword({
updatedFields: {
diff --git a/web/settings/tunnelbroker-test.react.js b/web/settings/tunnelbroker-test.react.js
--- a/web/settings/tunnelbroker-test.react.js
+++ b/web/settings/tunnelbroker-test.react.js
@@ -25,7 +25,7 @@
const messageInput = React.useRef(null);
const onSubmit = React.useCallback(
- async event => {
+ async (event: SyntheticEvent<HTMLButtonElement>) => {
event.preventDefault();
setLoading(true);
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
@@ -410,7 +410,7 @@
}, [messageTimestamp, tooltipActions]);
const createMessageTooltip = React.useCallback(
- tooltipPositionStyle => (
+ (tooltipPositionStyle: TooltipPositionStyle) => (
<MessageTooltip
actions={tooltipActions}
messageTimestamp={messageTimestamp}
diff --git a/web/utils/typeahead-utils.js b/web/utils/typeahead-utils.js
--- a/web/utils/typeahead-utils.js
+++ b/web/utils/typeahead-utils.js
@@ -75,14 +75,21 @@
caretLeftOffset,
};
}
-export type GetTypeaheadTooltipActionsParams<SuggestionItemType> = {
+type MentionTypeaheadSharedParams = {
+inputStateDraft: string,
+inputStateSetDraft: (draft: string) => mixed,
+inputStateSetTextCursorPosition: (newPosition: number) => mixed,
- +suggestions: $ReadOnlyArray<SuggestionItemType>,
+textBeforeAtSymbol: string,
+query: string,
};
+export type GetTypeaheadTooltipActionsParams<SuggestionItemType> = {
+ ...MentionTypeaheadSharedParams,
+ +suggestions: $ReadOnlyArray<SuggestionItemType>,
+};
+export type MentionTypeaheadTooltipActionExecuteHandlerParams = {
+ ...MentionTypeaheadSharedParams,
+ +mentionText: string,
+};
function mentionTypeaheadTooltipActionExecuteHandler({
textBeforeAtSymbol,
inputStateDraft,
@@ -90,7 +97,7 @@
mentionText,
inputStateSetDraft,
inputStateSetTextCursorPosition,
-}) {
+}: MentionTypeaheadTooltipActionExecuteHandlerParams) {
const { newText, newSelectionStart } = getNewTextAndSelection(
textBeforeAtSymbol,
inputStateDraft,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Dec 26, 8:17 AM (11 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2704599
Default Alt Text
D9771.id33161.diff (42 KB)
Attached To
Mode
D9771: [Flow202][web][skip-ci] [5/x] Address missing-local-annot type errors
Attached
Detach File
Event Timeline
Log In to Comment