diff --git a/web/src/api/hooks/annotations.ts b/web/src/api/hooks/annotations.ts index b0d1495de..bf56433ef 100644 --- a/web/src/api/hooks/annotations.ts +++ b/web/src/api/hooks/annotations.ts @@ -1,4 +1,10 @@ -import { CategoryDataAttrType, MutationHookType, PageInfo, QueryHookType } from 'api/typings'; +import { + AnnotationUserRevision, + CategoryDataAttrType, + MutationHookType, + PageInfo, + QueryHookType +} from 'api/typings'; import { Task } from 'api/typings/tasks'; import { useMutation, useQuery } from 'react-query'; import { useBadgerFetch } from './api'; @@ -70,6 +76,15 @@ export type AnnotationsByUserObj = PageInfo & { export type AnnotationsByUserResponse = { [page_num: number]: AnnotationsByUserObj[]; }; + +export type AnnotationAllUsersObject = { + [key: number]: AnnotationUserRevision[]; +}; + +type AnnotationAllUsersRequest = { + data: AnnotationAllUsersObject; +}; + export const useLatestAnnotations: QueryHookType = ( { jobId, fileId, revisionId, pageNumbers, userId }, options @@ -81,6 +96,15 @@ export const useLatestAnnotations: QueryHookType = ({ jobId, fileId, pageNumbers }) => { + return useQuery([jobId, fileId], async () => + fetchAnnotationAllUsers(jobId, fileId, pageNumbers) + ); +}; + export const useLatestAnnotationsByUser: QueryHookType< LatestAnnotationsParamsByUser, AnnotationsByUserResponse @@ -109,6 +133,18 @@ async function fetchLatestAnnotations( })(); } +async function fetchAnnotationAllUsers(jobId?: number, fileId?: number, pageNumbers?: number[]) { + if (!jobId || !fileId) { + return; + } + const pageNums = pageNumbers?.map((pageNumber) => `page_numbers=${pageNumber}`); + return useBadgerFetch({ + url: `${namespace}/annotation/${jobId}/${fileId}?${pageNums?.join('&')}`, + method: 'get', + withCredentials: true + })(); +} + async function fetchLatestAnnotationsByUser( jobId?: number, fileId?: number, diff --git a/web/src/api/typings.ts b/web/src/api/typings.ts index 166771e6d..f9e2b50e0 100644 --- a/web/src/api/typings.ts +++ b/web/src/api/typings.ts @@ -473,3 +473,15 @@ export type Report = { to: string; validationType: ValidationType | undefined; }; + +export type AnnotationUserRevision = { + categories: string[]; + date: string; + is_validated: boolean; + objs: PageInfoObjs; + page_num: number; + pipeline: number | null; + revision: string; + size: { width: number; height: number }; + user_id?: string | null; +}; diff --git a/web/src/components/split-labels-panel/split-labels-panel.tsx b/web/src/components/split-labels-panel/split-labels-panel.tsx index b32b35d9a..fb70c49ac 100644 --- a/web/src/components/split-labels-panel/split-labels-panel.tsx +++ b/web/src/components/split-labels-panel/split-labels-panel.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import { Tag, Spinner } from '@epam/loveship'; +import { Tag } from '@epam/loveship'; import styles from './split-labels-panel.module.scss'; import { Label } from 'api/typings'; import { useTaskAnnotatorContext } from 'connectors/task-annotator-connector/task-annotator-context'; @@ -11,10 +11,6 @@ type SplitLabelsPanelProps = { export const SplitLabelsPanel: FC = ({ labels, selectedLabelsId }) => { const { setTabValue, onLabelsSelected } = useTaskAnnotatorContext(); - if (!labels) { - return ; - } - const onClick = (id: string) => () => { setTabValue('Document'); onLabelsSelected(labels, [...selectedLabelsId, id]); @@ -22,7 +18,7 @@ export const SplitLabelsPanel: FC = ({ labels, selectedLa return (
- {labels.map(({ name, id }) => ( + {labels?.map(({ name, id }) => ( ))}
diff --git a/web/src/connectors/task-annotator-connector/task-annotator-context.tsx b/web/src/connectors/task-annotator-connector/task-annotator-context.tsx index c79adc31d..895ffc589 100644 --- a/web/src/connectors/task-annotator-connector/task-annotator-context.tsx +++ b/web/src/connectors/task-annotator-connector/task-annotator-context.tsx @@ -14,6 +14,7 @@ import { ApiError } from 'api/api-error'; import { DocumentLink, useAddAnnotationsMutation, + useAnnotationsAllUsers, useLatestAnnotations } from 'api/hooks/annotations'; import { useSetTaskFinishedMutation, useSetTaskState, useTaskById } from 'api/hooks/tasks'; @@ -61,6 +62,7 @@ import { getCategoryDataAttrs, isValidCategoryType, mapAnnDataAttrs, + mapAnnotationsByUsers, mapAnnotationDataAttrsFromApi, mapModifiedAnnotationPagesToApi, mapTokenPagesFromApi @@ -149,6 +151,7 @@ type ContextValue = SplitValidationValue & isDocLabelsModified: boolean; getJobId: () => number | undefined; linksFromApi?: DocumentLink[]; + allUsersAnnotation?: Map | undefined; }; type ProviderProps = { @@ -328,6 +331,14 @@ export const TaskAnnotatorContextProvider: React.FC = ({ { enabled: !!(task || job) } ); + const allUsersAnnotation = mapAnnotationsByUsers( + useAnnotationsAllUsers({ + jobId: getJobId(), + fileId: getFileId(), + pageNumbers: pageNumbers + })?.data + ); + const tokenRes = useTokens( { fileId: getFileId(), @@ -1066,6 +1077,7 @@ export const TaskAnnotatorContextProvider: React.FC = ({ latestLabelsId, setLatestLabelsId, linksFromApi, + allUsersAnnotation, ...splitValidation, ...syncScroll, ...documentLinksValues, diff --git a/web/src/connectors/task-annotator-connector/task-annotator-utils.ts b/web/src/connectors/task-annotator-connector/task-annotator-utils.ts index 86f730a9d..34b5379a0 100644 --- a/web/src/connectors/task-annotator-connector/task-annotator-utils.ts +++ b/web/src/connectors/task-annotator-connector/task-annotator-utils.ts @@ -8,6 +8,7 @@ import { ExternalViewerState, Taxon } from 'api/typings'; +import { AnnotationAllUsersObject } from 'api/hooks/annotations'; import { Annotation, AnnotationBoundType, AnnotationTable, PageToken, TableApi } from 'shared'; import { isIntersected, isR2InsideR1 } from 'shared/components/annotator/utils/is-intersected'; @@ -341,3 +342,15 @@ export const mapTokenPagesFromApi = ( }); return res; }; + +export const mapAnnotationsByUsers = (annotations?: AnnotationAllUsersObject) => { + if (annotations) { + const userAnnotationResult = new Map(); + Object.values(annotations).map((annotationData) => { + annotationData?.map((annotation) => { + userAnnotationResult.set(annotation.page_num, annotation.user_id); + }); + }); + return userAnnotationResult; + } +}; diff --git a/web/src/shared/components/document-pages/document-pages.tsx b/web/src/shared/components/document-pages/document-pages.tsx index 5be46a061..83e81c504 100644 --- a/web/src/shared/components/document-pages/document-pages.tsx +++ b/web/src/shared/components/document-pages/document-pages.tsx @@ -88,7 +88,8 @@ const DocumentPages: React.FC = ({ documentLinks, onLinkChanged, selectedRelatedDoc, - sortedUsers + allUsersAnnotation, + job } = useTaskAnnotatorContext(); const containerRef = useRef(null); @@ -100,9 +101,8 @@ const DocumentPages: React.FC = ({ const selectedLabelsId = selectedLabels?.map(({ id }) => id) || []; const getAnnotatorName = useCallback( - (annotatorId: string): string => - sortedUsers.current.annotators.find(({ id }) => id === annotatorId)?.username || '', - [sortedUsers] + (annotatorId: string): string => job?.annotators.find((el) => el === annotatorId) || '', + [job] ); useEffect(() => { @@ -157,6 +157,15 @@ const DocumentPages: React.FC = ({ ); + const displayAnnotatorInfo = (userId?: string) => + task?.is_validation && ( + + ); + return ( <> {selectedRelatedDoc ? ( @@ -200,11 +209,7 @@ const DocumentPages: React.FC = ({ {userPages.map(({ user_id, page_num }) => ( - + {displayAnnotatorInfo(user_id)} = ({ {pageNumbers.map((pageNum) => { return ( + {displayAnnotatorInfo( + allUsersAnnotation?.get(pageNum) + )} = ({ {pageNumbers.map((pageNum) => { return ( + {displayAnnotatorInfo( + allUsersAnnotation?.get(pageNum) + )}