diff --git a/frontend/packages/data-portal/app/components/Run/AnnotationTable.tsx b/frontend/packages/data-portal/app/components/Run/AnnotationTable.tsx index 82f15fd34..caec07199 100644 --- a/frontend/packages/data-portal/app/components/Run/AnnotationTable.tsx +++ b/frontend/packages/data-portal/app/components/Run/AnnotationTable.tsx @@ -1,13 +1,15 @@ /* eslint-disable react/no-unstable-nested-components */ import { Button, Icon } from '@czi-sds/components' +import { useSearchParams } from '@remix-run/react' import { ColumnDef, createColumnHelper, Row, Table, } from '@tanstack/react-table' -import { range } from 'lodash-es' +import { t } from 'i18next' +import { range, toNumber } from 'lodash-es' import { ComponentProps, ReactNode, useCallback, useMemo } from 'react' import { AuthorList } from 'app/components/AuthorList' @@ -21,6 +23,7 @@ import { MethodType, } from 'app/constants/methodTypes' import { MAX_PER_PAGE } from 'app/constants/pagination' +import { QueryParams } from 'app/constants/query' import { AnnotationTableWidths } from 'app/constants/table' import { TestIds } from 'app/constants/testIds' import { useDownloadModalQueryParamState } from 'app/hooks/useDownloadModalQueryParamState' @@ -35,6 +38,8 @@ import { Annotation, useAnnotation } from 'app/state/annotation' import { I18nKeys } from 'app/types/i18n' import { cns, cnsNoMerge } from 'app/utils/cns' +import { DatasetAuthors } from '../Dataset/DatasetAuthors' + const LOADING_ANNOTATIONS = range(0, MAX_PER_PAGE).map(() => ({ annotation_method: '', author_affiliations: [], @@ -70,6 +75,7 @@ function ConfidenceValue({ value }: { value: number }) { export function AnnotationTable() { const { isLoadingDebounced } = useIsLoading() + const [searchParams] = useSearchParams() const { run, annotationFilesAggregates } = useRunById() const { toggleDrawer } = useMetadataDrawer() const { setActiveAnnotation } = useAnnotation() @@ -387,39 +393,63 @@ export function AnnotationTable() { [run.annotation_table], ) - const getGroundTruthDivider = ( + const currentPage = toNumber( + searchParams.get(QueryParams.AnnotationsPage) ?? 1, + ) + + /** + * Attaches divider(s) before a row. + * - The ground truth divider can only be shown on the first row. + * - The first page always shows the divider, even if there are 0 ground truth rows. + * - Subsequent pages only show the divider if the first row is ground truth. + * - The non ground truth divider is shown before the first non ground truth row. + */ + const getGroundTruthDividersForRow = ( table: Table, row: Row, ): ReactNode => { - const { rows } = table.getRowModel() - let dividerText - - // Show before first ground truth row: - if (row.id === rows.find((r) => r.original.ground_truth_status)?.id) { - dividerText = t('groundTruthAnnotations', { - count: annotationFilesAggregates.groundTruthCount, - }) - } - // Show before first non ground truth row: - if (row.id === rows.find((r) => !r.original.ground_truth_status)?.id) { - dividerText = t('otherAnnotations', { - count: annotationFilesAggregates.otherCount, - }) - } - - if (dividerText === undefined) { - return null - } + return ( + <> + {row.index === 0 && + (currentPage === 1 || row.original.ground_truth_status) && ( + + )} + + {row.id === + table.getRowModel().rows.find((r) => !r.original.ground_truth_status) + ?.id && ( + + )} + + ) + } + /** + * Adds dividers to the end of the table when there are no rows to attach them to. + * - The ground truth divider won't have a row to attach to only if there are 0 rows in the + * table. + * - The non ground truth divider won't have a row to attach to only if there are 0 non ground + * truth rows in the table and this is the last page. + */ + const getGroundTruthDividersWhenNoRows = (): ReactNode => { return ( - - - {dividerText} - - + <> + {annotationFilesAggregates.filteredCount === 0 && ( + + )} + + {annotationFilesAggregates.otherCount === 0 && + annotationFilesAggregates.filteredCount <= + currentPage * MAX_PER_PAGE && ( + + )} + ) } @@ -427,8 +457,30 @@ export function AnnotationTable() { ) } + +function RowDivider({ + groundTruth, + count, +}: { + groundTruth: boolean + count: number +}) { + return ( + + + {t(groundTruth ? 'groundTruthAnnotations' : 'otherAnnotations', { + count, + })} + + + ) +} diff --git a/frontend/packages/data-portal/app/components/Table/Table.tsx b/frontend/packages/data-portal/app/components/Table/Table.tsx index 30093900f..e2872e982 100644 --- a/frontend/packages/data-portal/app/components/Table/Table.tsx +++ b/frontend/packages/data-portal/app/components/Table/Table.tsx @@ -33,6 +33,7 @@ export interface TableProps { data: T[] tableProps?: SDSTableProps getBeforeRowElement?: (table: ReactTable, row: Row) => ReactNode + getAfterTableElement?: (table: ReactTable) => ReactNode onTableRowClick?(row: Row): void } @@ -42,6 +43,7 @@ export function Table({ data, tableProps, getBeforeRowElement, + getAfterTableElement, onTableRowClick, }: TableProps) { const { hasFilters } = useLayout() @@ -109,6 +111,8 @@ export function Table({ ))} + + {getAfterTableElement?.(table)} diff --git a/frontend/packages/data-portal/tsconfig.json b/frontend/packages/data-portal/tsconfig.json index 3960b5958..af71c7725 100644 --- a/frontend/packages/data-portal/tsconfig.json +++ b/frontend/packages/data-portal/tsconfig.json @@ -2,7 +2,6 @@ "compilerOptions": { "baseUrl": ".", "allowJs": true, - "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "react-jsx",