Skip to content

Commit

Permalink
refactor(content-sidebar): convert annotation-thread to TypeScript
Browse files Browse the repository at this point in the history
- Converted all JS files in annotation-thread directory to TypeScript
- Added Flow type definition files for backward compatibility
- Updated function signatures to use object parameters
- Added proper TypeScript interfaces and types
- Removed Flow-specific syntax and comments
  • Loading branch information
devin-ai-integration[bot] committed Feb 24, 2025
1 parent 8cf5e9f commit 03a046d
Show file tree
Hide file tree
Showing 17 changed files with 1,324 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ type Props = {
onHideReplies?: (lastReply: CommentType) => void,
onReplyCreate?: (text: string) => void,
onReplyDelete?: ({ id: string, permissions: BoxCommentPermission }) => void,
onReplyEdit?: (
onReplyEdit?: ({
id: string,
text: string,
permissions: BoxCommentPermission,
status?: FeedItemStatus,
hasMention?: boolean,
permissions: BoxCommentPermission,
onSuccess: ?Function,
onError: ?Function,
) => void,
onSuccess?: Function,
onError?: Function,
}) => void,
onReplySelect?: (isSelected: boolean) => void,
onShowReplies?: () => void,
replies?: Array<CommentType>,
Expand Down Expand Up @@ -140,7 +140,9 @@ const ActivityThread = ({
isRepliesLoading={isRepliesLoading}
mentionSelectorContacts={mentionSelectorContacts}
onDelete={onReplyDelete}
onEdit={onReplyEdit}
onEdit={(id, text, status, hasMention, permissions, onSuccess, onError) =>
onReplyEdit({ id, text, permissions, status, hasMention, onSuccess, onError })
}
onSelect={onReplySelect}
replies={replies}
translations={translations}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// @flow
import * as React from 'react';
import type { GetAvatarUrlCallback, GetProfileUrlCallback } from '../../../common/flowTypes';
import type { Translations } from '../../flowTypes';
import type { SelectorItems, User } from '../../../../common/types/core';
import type { BoxCommentPermission, Comment as CommentType, FeedItemStatus } from '../../../../common/types/feed';

type Props = {
children: React.Node,
currentUser?: User,
getAvatarUrl: GetAvatarUrlCallback,
getMentionWithQuery?: Function,
getUserProfileUrl?: GetProfileUrlCallback,
hasNewThreadedReplies?: boolean,
hasReplies: boolean,
isAlwaysExpanded?: boolean,
isPending?: boolean,
isRepliesLoading?: boolean,
mentionSelectorContacts?: SelectorItems<>,
onHideReplies?: (lastReply: CommentType) => void,
onReplyCreate?: (text: string) => void,
onReplyDelete?: ({ id: string, permissions: BoxCommentPermission }) => void,
onReplyEdit?: ({
id: string,
text: string,
permissions: BoxCommentPermission,
status?: FeedItemStatus,
hasMention?: boolean,
onSuccess?: Function,
onError?: Function,
}) => void,
onReplySelect?: (isSelected: boolean) => void,
onShowReplies?: () => void,
replies?: Array<CommentType>,
repliesTotalCount?: number,
translations?: Translations,
};

declare export default React.ComponentType<Props>;
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ type Props = {
isRepliesLoading?: boolean,
mentionSelectorContacts?: SelectorItems<>,
onDelete?: Function,
onEdit?: Function,
onEdit?: ({
id: string,
text: string,
permissions: BoxCommentPermission,
status?: FeedItemStatus,
hasMention?: boolean,
onSuccess?: Function,
onError?: Function,
}) => void,
onSelect?: (isSelected: boolean) => void,
replies: Array<CommentType>,
translations?: Translations,
Expand Down Expand Up @@ -49,9 +57,17 @@ const ActivityThreadReplies = ({
};
};

const handleOnEdit = ({ hasMention, id, onError, onSuccess, permissions, status, text }): void => {
const handleOnEdit = (params: {
hasMention?: boolean,
id: string,
onError?: Function,
onSuccess?: Function,
permissions: BoxCommentPermission,
status?: FeedItemStatus,
text: string,
}): void => {
if (onEdit) {
onEdit(id, text, status, hasMention, permissions, onSuccess, onError);
onEdit(params);
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// @flow
import * as React from 'react';
import type { GetAvatarUrlCallback, GetProfileUrlCallback } from '../../../common/flowTypes';
import type { Translations } from '../../flowTypes';
import type { SelectorItems, User } from '../../../../common/types/core';
import type { BoxCommentPermission, Comment as CommentType, FeedItemStatus } from '../../../../common/types/feed';

type Props = {
currentUser?: User,
getAvatarUrl: GetAvatarUrlCallback,
getMentionWithQuery?: Function,
getUserProfileUrl?: GetProfileUrlCallback,
hasNewThreadedReplies?: boolean,
isRepliesLoading?: boolean,
mentionSelectorContacts?: SelectorItems<>,
onDelete?: Function,
onEdit?: ({
id: string,
text: string,
permissions: BoxCommentPermission,
status?: FeedItemStatus,
hasMention?: boolean,
onSuccess?: Function,
onError?: Function,
}) => void,
onSelect?: (isSelected: boolean) => void,
replies: Array<CommentType>,
translations?: Translations,
};

declare export default React.ComponentType<Props>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @flow
import * as React from 'react';
import type { EventEmitter } from 'events';
import type { APICache } from '../../../../utils/Cache';
import type { BoxItem, SelectorItems, StringMap, Token, User } from '../../../../common/types/core';
import type { ElementOrigin, ElementsXhrError } from '../../../../common/types/api';
import type { Annotation, Target } from '../../../../common/types/annotations';
import type { GetProfileUrlCallback } from '../../../common/flowTypes';

type Props = {
annotationId?: string,
apiHost?: string,
cache?: APICache,
className?: string,
clientName: string,
currentUser: User,
eventEmitter: EventEmitter,
file: BoxItem,
getUserProfileUrl?: GetProfileUrlCallback,
handleCancel: () => void,
language?: string,
messages?: StringMap,
onAnnotationCreate: (annotation: Annotation) => void,
onError: (error: ElementsXhrError | Error, code: string, contextInfo?: Object, origin?: ElementOrigin) => void,
target: Target,
token: Token,
};

declare export default React.ComponentType<Props>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import * as React from 'react';
import debounce from 'lodash/debounce';
import classNames from 'classnames';
import { IntlProvider } from 'react-intl';
import { EventEmitter } from 'events';
import AnnotationThreadContent from './AnnotationThreadContent';
import AnnotationThreadCreate from './AnnotationThreadCreate';
import useAnnotationThread from './useAnnotationThread';
import API from '../../../../api/APIFactory';
import { DEFAULT_COLLAB_DEBOUNCE, DEFAULT_HOSTNAME_API } from '../../../../constants';

import { APICache } from '../../../../utils/Cache';
import { BoxItem, SelectorItems, StringMap, Token, User } from '../../../../common/types/core';
import { ElementOrigin, ElementsXhrError } from '../../../../common/types/api';
import { Annotation, Target } from '../../../../common/types/annotations';
import { GetProfileUrlCallback } from '../../../common/flowTypes';

import './AnnotationThread.scss';

interface AnnotationThreadProps {
annotationId?: string;
apiHost?: string;
cache?: APICache;
className?: string;
clientName: string;
currentUser: User;
eventEmitter: EventEmitter;
file: BoxItem;
getUserProfileUrl?: GetProfileUrlCallback;
handleCancel: () => void;
language?: string;
messages?: StringMap;
onAnnotationCreate: (annotation: Annotation) => void;
onError: (
error: ElementsXhrError | Error,
code: string,
contextInfo?: Record<string, unknown>,
origin?: ElementOrigin,
) => void;
target: Target;
token: Token;
}

const AnnotationThread = ({
annotationId,
apiHost = DEFAULT_HOSTNAME_API,
cache,
className = '',
clientName,
currentUser,
eventEmitter,
file,
getUserProfileUrl,
handleCancel,
language,
messages,
onAnnotationCreate,
onError,
target,
token,
}: AnnotationThreadProps) => {
const [mentionSelectorContacts, setMentionSelectorContacts] = React.useState<SelectorItems[]>([]);

const api = new API({
apiHost,
cache,
clientName,
language,
token,
});

const {
annotation,
replies,
isLoading,
error,
annotationActions: {
handleAnnotationCreate,
handleAnnotationDelete,
handleAnnotationEdit,
handleAnnotationStatusChange,
},
repliesActions: { handleReplyEdit, handleReplyCreate, handleReplyDelete },
} = useAnnotationThread({
api,
annotationId,
currentUser,
errorCallback: onError,
eventEmitter,
file,
onAnnotationCreate,
target,
});

const getAvatarUrl = async (userId: string): Promise<string | null> =>
api.getUsersAPI(false).getAvatarUrlWithAccessToken(userId, file.id);

const getMentionContactsSuccessCallback = ({ entries }: { entries: SelectorItems[] }): void => {
setMentionSelectorContacts(entries);
};

const getMentionWithQuery = debounce(searchStr => {
api.getFileCollaboratorsAPI(false).getCollaboratorsWithQuery(
file.id,
getMentionContactsSuccessCallback,
onError,
searchStr,
);
}, DEFAULT_COLLAB_DEBOUNCE);

return (
<div className={classNames('AnnotationThread', className)} data-testid="annotation-thread">
<IntlProvider locale={language} messages={messages}>
{!annotationId ? (
<AnnotationThreadCreate
currentUser={currentUser}
getAvatarUrl={getAvatarUrl}
getMentionWithQuery={getMentionWithQuery}
isPending={isLoading}
mentionSelectorContacts={mentionSelectorContacts}
onFormCancel={handleCancel}
onFormSubmit={handleAnnotationCreate}
/>
) : (
<AnnotationThreadContent
annotation={annotation}
currentUser={currentUser}
error={error}
getAvatarUrl={getAvatarUrl}
getMentionWithQuery={getMentionWithQuery}
getUserProfileUrl={getUserProfileUrl}
isLoading={isLoading}
mentionSelectorContacts={mentionSelectorContacts}
onAnnotationDelete={handleAnnotationDelete}
onAnnotationEdit={handleAnnotationEdit}
onAnnotationStatusChange={handleAnnotationStatusChange}
onReplyCreate={handleReplyCreate}
onReplyDelete={handleReplyDelete}
onReplyEdit={handleReplyEdit}
replies={replies}
/>
)}
</IntlProvider>
</div>
);
};

export default AnnotationThread;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// @flow
import * as React from 'react';
import type {
Annotation,
AnnotationPermission,
BoxCommentPermission,
Comment,
FeedItemStatus,
} from '../../../../common/types/feed';
import type { SelectorItems, User } from '../../../../common/types/core';
import type { GetProfileUrlCallback } from '../../../common/flowTypes';
import type { AnnotationThreadError } from './types';
import type { OnAnnotationEdit, OnAnnotationStatusChange } from '../comment/types';

type Props = {
annotation?: Annotation,
currentUser: User,
error?: AnnotationThreadError,
getAvatarUrl: string => Promise<?string>,
getMentionWithQuery: (searchStr: string) => void,
getUserProfileUrl?: GetProfileUrlCallback,
isLoading: boolean,
mentionSelectorContacts: SelectorItems<>,
onAnnotationDelete?: ({ id: string, permissions: AnnotationPermission }) => any,
onAnnotationEdit?: OnAnnotationEdit,
onAnnotationStatusChange: OnAnnotationStatusChange,
onReplyCreate?: (text: string) => void,
onReplyDelete?: ({ id: string, permissions: BoxCommentPermission }) => void,
onReplyEdit?: (
id: string,
text: string,
status?: FeedItemStatus,
hasMention?: boolean,
permissions: BoxCommentPermission,
onSuccess: ?Function,
onError: ?Function,
) => void,
replies?: Array<Comment>,
};

declare export default React.ComponentType<Props>;
Loading

0 comments on commit 03a046d

Please sign in to comment.