From 62fb35fe2a59215387c29e36cfb62d1b6ed7a9a9 Mon Sep 17 00:00:00 2001 From: Kira Evans Date: Wed, 21 Aug 2024 15:48:36 -0700 Subject: [PATCH] feat: add single deposition info panel (#986) #926 - fix/refactor various components - add info panel - add deposition overview metadata table - add annotations summary metadata table - add annotations methods summary metadata table https://github.com/user-attachments/assets/e78dd5b3-4555-4b34-895b-7f93beb74ff7 --- .../app/components/AccordionMetadataTable.tsx | 2 +- .../app/components/AuthorLink/AuthorLink.tsx | 6 +- .../components/BrowseData/DepositionTable.tsx | 3 +- .../app/components/CollapsibleList.tsx | 8 +- .../app/components/DatabaseEntry.tsx | 14 ++ .../Dataset/DatasetMetadataDrawer.tsx | 5 +- .../Dataset/DatasetMetadataTable.tsx | 52 ++-- .../AnnotationsSummaryMetadataTable.tsx | 110 +++++++++ .../Deposition/DepositionMetadataDrawer.tsx | 25 ++ .../Deposition/DepositionMetadataTable.tsx | 115 +++++++++ .../Deposition/DepositionOverview.tsx | 4 +- .../MethodLinks/MethodLinksMetadataTable.tsx | 226 ++++++++++++++++++ .../MethodLinksOverview.tsx} | 86 +------ .../Deposition/MethodLinks/common.tsx | 83 +++++++ .../Deposition/MethodLinks/index.ts | 2 + .../app/components/Deposition/index.ts | 1 + .../app/components/Run/RunMetadataDrawer.tsx | 2 +- .../app/constants/objectShapeTypes.ts | 14 +- .../app/routes/depositions.$id.tsx | 2 + .../data-portal/app/types/shapeTypes.ts | 5 + .../public/locales/en/translation.json | 16 +- 21 files changed, 652 insertions(+), 129 deletions(-) create mode 100644 frontend/packages/data-portal/app/components/Deposition/AnnotationsSummaryMetadataTable.tsx create mode 100644 frontend/packages/data-portal/app/components/Deposition/DepositionMetadataDrawer.tsx create mode 100644 frontend/packages/data-portal/app/components/Deposition/DepositionMetadataTable.tsx create mode 100644 frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksMetadataTable.tsx rename frontend/packages/data-portal/app/components/Deposition/{AnnotationMethodsSummary.tsx => MethodLinks/MethodLinksOverview.tsx} (73%) create mode 100644 frontend/packages/data-portal/app/components/Deposition/MethodLinks/common.tsx create mode 100644 frontend/packages/data-portal/app/components/Deposition/MethodLinks/index.ts create mode 100644 frontend/packages/data-portal/app/types/shapeTypes.ts diff --git a/frontend/packages/data-portal/app/components/AccordionMetadataTable.tsx b/frontend/packages/data-portal/app/components/AccordionMetadataTable.tsx index d413e441b..75e2b8bc6 100644 --- a/frontend/packages/data-portal/app/components/AccordionMetadataTable.tsx +++ b/frontend/packages/data-portal/app/components/AccordionMetadataTable.tsx @@ -28,7 +28,7 @@ export function AccordionMetadataTable({ data={data} tableCellLabelProps={{ renderLoadingSkeleton: false, - width: { min: COLUMN_WIDTH, max: COLUMN_WIDTH }, + width: { min: COLUMN_WIDTH, width: COLUMN_WIDTH, max: COLUMN_WIDTH }, ...tableCellLabelProps, }} tableCellValueProps={{ diff --git a/frontend/packages/data-portal/app/components/AuthorLink/AuthorLink.tsx b/frontend/packages/data-portal/app/components/AuthorLink/AuthorLink.tsx index 072708689..c7660ae96 100644 --- a/frontend/packages/data-portal/app/components/AuthorLink/AuthorLink.tsx +++ b/frontend/packages/data-portal/app/components/AuthorLink/AuthorLink.tsx @@ -39,12 +39,10 @@ export function AuthorLink({ )} > {author.orcid && ( - + )} - - {author.name} - + {author.name} {author.corresponding_author_status && ( diff --git a/frontend/packages/data-portal/app/components/BrowseData/DepositionTable.tsx b/frontend/packages/data-portal/app/components/BrowseData/DepositionTable.tsx index 278d0ab60..adec7c84b 100644 --- a/frontend/packages/data-portal/app/components/BrowseData/DepositionTable.tsx +++ b/frontend/packages/data-portal/app/components/BrowseData/DepositionTable.tsx @@ -18,7 +18,6 @@ import { DepositionTableWidths } from 'app/constants/table' import { Deposition, useDepositions } from 'app/hooks/useDepositions' import { useI18n } from 'app/hooks/useI18n' import { useIsLoading } from 'app/hooks/useIsLoading' -import { I18nKeys } from 'app/types/i18n' import { LogLevel } from 'app/types/logging' import { cnsNoMerge } from 'app/utils/cns' import { sendLogs } from 'app/utils/logging' @@ -295,7 +294,7 @@ export function DepositionTable() { className="whitespace-nowrap overflow-x-hidden overflow-ellipsis" key={entry[0]} > - {t(entry[1] as I18nKeys)} + {t(entry[1])} ))} diff --git a/frontend/packages/data-portal/app/components/CollapsibleList.tsx b/frontend/packages/data-portal/app/components/CollapsibleList.tsx index 0a0867008..79e0ba13f 100644 --- a/frontend/packages/data-portal/app/components/CollapsibleList.tsx +++ b/frontend/packages/data-portal/app/components/CollapsibleList.tsx @@ -45,7 +45,9 @@ export function CollapsibleList({ className={cns( 'flex', inlineVariant ? 'flex-wrap gap-sds-xxs' : 'flex-col gap-sds-xs', - 'text-sds-body-xxs leading-sds-body-xxs', + tableVariant + ? 'text-sds-body-s leading-sds-body-s' + : 'text-sds-body-xxs leading-sds-body-xxs', collapsible && 'transition-[max-height_0.2s_ease-out]', )} > @@ -83,7 +85,9 @@ export function CollapsibleList({ sdsType="static" className="!text-current" /> - {t('showMore', { count: entries.length - collapseAfter })} + {t('showNumberMore', { + count: entries.length - collapseAfter, + })} ) : ( <> diff --git a/frontend/packages/data-portal/app/components/DatabaseEntry.tsx b/frontend/packages/data-portal/app/components/DatabaseEntry.tsx index 5b097ab58..add8bd07c 100644 --- a/frontend/packages/data-portal/app/components/DatabaseEntry.tsx +++ b/frontend/packages/data-portal/app/components/DatabaseEntry.tsx @@ -51,3 +51,17 @@ export function DatabaseEntry(props: DatabaseEntryProps) {

) } + +export function DatabaseEntryList({ entries }: { entries: string }) { + return ( +
    + {entries.split(',').map((entry) => { + return ( +
  • + +
  • + ) + })} +
+ ) +} diff --git a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx index df28da6e5..a29236035 100644 --- a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx @@ -1,20 +1,21 @@ import { MetadataDrawer } from 'app/components/MetadataDrawer' import { useDatasetById } from 'app/hooks/useDatasetById' +import { useI18n } from 'app/hooks/useI18n' import { MetadataDrawerId } from 'app/hooks/useMetadataDrawer' -import { i18n } from 'app/i18n' import { DatasetMetadataTable } from './DatasetMetadataTable' import { DatasetTiltSeriesTable } from './DatasetTiltSeriesTable' import { SampleAndExperimentConditionsTable } from './SampleAndExperimentConditionsTable' export function DatasetMetadataDrawer() { + const { t } = useI18n() const { dataset } = useDatasetById() return ( diff --git a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx index 0c3d16f91..2fc916c63 100644 --- a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx @@ -5,44 +5,28 @@ import { AccordionMetadataTable } from 'app/components/AccordionMetadataTable' import { AuthorLegend } from 'app/components/AuthorLegend' import { AuthorInfo } from 'app/components/AuthorLink' import { AuthorList } from 'app/components/AuthorList' -import { DatabaseEntry } from 'app/components/DatabaseEntry' +import { DatabaseEntryList } from 'app/components/DatabaseEntry' import { Link } from 'app/components/Link' import { useI18n } from 'app/hooks/useI18n' import { getTableData } from 'app/utils/table' import { DatasetType } from './type' -function DatabaseEntryList({ entries }: { entries: string }) { - return ( -
    - {entries.split(',').map((entry) => { - return ( -
  • - -
  • - ) - })} -
- ) -} - -interface DatasetMetadataTableProps { - dataset: DatasetType - allFields?: boolean - initialOpen?: boolean -} - export function DatasetMetadataTable({ dataset, - allFields, + showAllFields, initialOpen, -}: DatasetMetadataTableProps) { +}: { + dataset: DatasetType + showAllFields?: boolean + initialOpen?: boolean +}) { const { t } = useI18n() const datasetMetadata = getTableData( - !!allFields && { + !!showAllFields && { label: t('datasetTitle'), - values: [dataset.title!], + values: [dataset.title ?? ''], renderValue: (value) => { return ( { @@ -140,7 +124,7 @@ export function DatasetMetadataTable({ return ( diff --git a/frontend/packages/data-portal/app/components/Deposition/AnnotationsSummaryMetadataTable.tsx b/frontend/packages/data-portal/app/components/Deposition/AnnotationsSummaryMetadataTable.tsx new file mode 100644 index 000000000..6c566dc47 --- /dev/null +++ b/frontend/packages/data-portal/app/components/Deposition/AnnotationsSummaryMetadataTable.tsx @@ -0,0 +1,110 @@ +import { AccordionMetadataTable } from 'app/components/AccordionMetadataTable' +import { CollapsibleList } from 'app/components/CollapsibleList' +import { shapeTypeToI18nKeyPlural } from 'app/constants/objectShapeTypes' +import { useI18n } from 'app/hooks/useI18n' +import { getTableData } from 'app/utils/table' + +export function AnnotationsSummaryMetadataTable({ + initialOpen, +}: { + initialOpen?: boolean +}) { + const { t } = useI18n() + + // TODO: replace this when backend data hooked up + const fakeListData = [ + { + key: '1', + entry: 'dfasdfsdf', + }, + { + key: '2', + entry: 'werweqe', + }, + { + key: '3', + entry: 'fdsgfdg', + }, + { + key: '4', + entry: 'dfghdfgh', + }, + { + key: '5', + entry: 'fghjgfhjfghj', + }, + { + key: '6', + entry: 'ryturtyu', + }, + { + key: '7', + entry: 'ertyery', + }, + ] + + const annotationsSummaryMetadata = getTableData( + { + label: t('annotationsTotal'), + // TODO: replace this when backend data hooked up + values: [(10000).toLocaleString()], + }, + + { + label: t('annotatedOrganisms'), + values: [], + renderValue: () => ( + + ), + }, + + { + label: t('annotatedObjects'), + values: [], + renderValue: () => ( + + ), + }, + + { + label: t('objectShapeTypes'), + values: [], + renderValue: () => { + // TODO: replace this when backend data hooked up + const shapeTypes = [ + 'InstanceSegmentation', + 'OrientedPoint', + 'Point', + 'SegmentationMask', + ] + + return ( +
    + {Object.entries(shapeTypeToI18nKeyPlural) + .filter(([k]) => shapeTypes.includes(k)) + .map(([k, v]) => ( +
  • {t(v)}
  • + ))} +
+ ) + }, + }, + ) + + return ( + + ) +} diff --git a/frontend/packages/data-portal/app/components/Deposition/DepositionMetadataDrawer.tsx b/frontend/packages/data-portal/app/components/Deposition/DepositionMetadataDrawer.tsx new file mode 100644 index 000000000..ac45081fe --- /dev/null +++ b/frontend/packages/data-portal/app/components/Deposition/DepositionMetadataDrawer.tsx @@ -0,0 +1,25 @@ +import { MetadataDrawer } from 'app/components/MetadataDrawer' +import { useDepositionById } from 'app/hooks/useDepositionById' +import { useI18n } from 'app/hooks/useI18n' +import { MetadataDrawerId } from 'app/hooks/useMetadataDrawer' + +import { AnnotationsSummaryMetadataTable } from './AnnotationsSummaryMetadataTable' +import { DepositionMetadataTable } from './DepositionMetadataTable' +import { MethodLinksMetadataTable } from './MethodLinks' + +export function DepositionMetadataDrawer() { + const { t } = useI18n() + const { deposition } = useDepositionById() + + return ( + + + + + + ) +} diff --git a/frontend/packages/data-portal/app/components/Deposition/DepositionMetadataTable.tsx b/frontend/packages/data-portal/app/components/Deposition/DepositionMetadataTable.tsx new file mode 100644 index 000000000..14a36dc8e --- /dev/null +++ b/frontend/packages/data-portal/app/components/Deposition/DepositionMetadataTable.tsx @@ -0,0 +1,115 @@ +import { Icon } from '@czi-sds/components' +import { useState } from 'react' + +import { AccordionMetadataTable } from 'app/components/AccordionMetadataTable' +import { AuthorLegend } from 'app/components/AuthorLegend' +import { AuthorInfo } from 'app/components/AuthorLink' +import { AuthorList } from 'app/components/AuthorList' +import { DatabaseEntryList } from 'app/components/DatabaseEntry' +import { Deposition } from 'app/hooks/useDepositionById' +import { useI18n } from 'app/hooks/useI18n' +import { getTableData } from 'app/utils/table' + +function CollapsibleDescription({ text }: { text: string }) { + const { t } = useI18n() + const [isCollapsed, setCollapsed] = useState(true) + + return ( +
+

+ {text} +

+
+ +
+
+ ) +} + +export function DepositionMetadataTable({ + deposition, + initialOpen, +}: { + deposition: Deposition + initialOpen?: boolean +}) { + const { t } = useI18n() + + const depositionMetadata = getTableData( + { + label: t('depositionId'), + values: [`CZCPD-${deposition.id}`], + }, + + { + label: + deposition.authors && deposition.authors.length === 1 + ? t('author') + : t('authors'), + labelExtra: , + renderValue: () => { + return + }, + values: [], + className: 'leading-sds-body-s', + }, + + { + label: t('publications'), + values: [deposition.deposition_publications ?? ''], + renderValue: (value: string) => { + return + }, + }, + + { + label: t('relatedDatabases'), + values: [deposition.related_database_entries ?? ''], + renderValue: (value: string) => { + return + }, + }, + + { + label: t('description'), + values: [deposition.description], + renderValue: (value: string) => { + return + }, + }, + + { + label: t('depositionDate'), + values: [deposition.deposition_date], + }, + + { + label: t('releaseDate'), + values: [deposition.release_date], + }, + + { + label: t('lastModifiedDate'), + values: [deposition.last_modified_date ?? ''], + }, + ) + + return ( + + ) +} diff --git a/frontend/packages/data-portal/app/components/Deposition/DepositionOverview.tsx b/frontend/packages/data-portal/app/components/Deposition/DepositionOverview.tsx index ffc762f64..ebe1c30d2 100644 --- a/frontend/packages/data-portal/app/components/Deposition/DepositionOverview.tsx +++ b/frontend/packages/data-portal/app/components/Deposition/DepositionOverview.tsx @@ -10,7 +10,7 @@ import { useDepositionById } from 'app/hooks/useDepositionById' import { useI18n } from 'app/hooks/useI18n' import { cnsNoMerge } from 'app/utils/cns' -import { AnnotationMethodsSummary } from './AnnotationMethodsSummary' +import { MethodLinksOverview } from './MethodLinks' // use clsx here instead of cns since it erroneously merges text-sds-gray-500 and text-sds-caps-xxxs const sectionHeaderStyles = cnsNoMerge( @@ -96,7 +96,7 @@ export function DepositionOverview() { - + ) } diff --git a/frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksMetadataTable.tsx b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksMetadataTable.tsx new file mode 100644 index 000000000..c83d7dfa4 --- /dev/null +++ b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksMetadataTable.tsx @@ -0,0 +1,226 @@ +import { useMemo } from 'react' + +import { Accordion } from 'app/components/Accordion' +import { Link } from 'app/components/Link' +import { MetadataTable } from 'app/components/Table' +import { methodLabels, MethodType } from 'app/constants/methodTypes' +import { useI18n } from 'app/hooks/useI18n' +import { getTableData } from 'app/utils/table' + +import { generateMethodLinks, MethodLinkVariantProps } from './common' + +const COLUMN_WIDTH = 170 + +type MethodDataType = { + method_type: MethodType + annotations_count: number + method_description: string + annotation_software: string + links: MethodLinkVariantProps[] +} + +function MethodLinkList({ + links: variantLinks, +}: { + links: MethodLinkVariantProps[] +}) { + const links = useMemo(() => generateMethodLinks(variantLinks), [variantLinks]) + + const { t } = useI18n() + + if (links.length === 0) { + return ( +

+ {t('notSubmitted')} +

+ ) + } + + return ( +
    + {links.map((link) => ( +
  • + + + {link.icon} + + {t(link.i18nLabel)}: + + + + {link.title ?? link.url} + + +
  • + ))} +
+ ) +} + +function MethodSummarySection({ + label, + data, +}: { + label?: string + data: MethodDataType +}) { + const { t } = useI18n() + + const tableData = getTableData( + { + label: t('methodType'), + values: [t(methodLabels[data.method_type])], + }, + { + label: t('numberOfAnnotations'), + values: [data.annotations_count.toLocaleString()], + }, + { + label: t('annotationMethod'), + values: [data.method_description], + }, + { + label: t('annotationSoftware'), + values: [data.annotation_software], + }, + { + label: t('methodLinks'), + values: [], + renderValue: () => , + }, + ) + + return ( +
+ {label && ( +
+

+ {label} +

+
+
+ )} + +
+ ) +} + +export function MethodLinksMetadataTable({ + initialOpen = true, +}: { + initialOpen?: boolean +}) { + const { t } = useI18n() + + const methodOne: MethodDataType = { + method_type: 'hybrid', + annotations_count: 3000, + method_description: + 'Cumulative template-matching trained 2D CNN predictions + visual filtering + distance constraints + manual addition', + annotation_software: 'pyTOM + Keras', + links: [ + { + variant: 'sourceCode', + title: 'My model’s source code', + url: 'https://example.com', + }, + { + variant: 'sourceCode', + title: 'Lorem-Ispum3-Dolor-V-2_5', + url: 'https://example.com', + }, + { + variant: 'modelWeights', + title: 'Model Weights for model Lorem-Ispum3-Dolor-V-2_5', + url: 'https://example.com', + }, + { + variant: 'website', + url: 'www.url.com', + }, + { + variant: 'documentation', + title: 'How to Use', + url: 'https://example.com', + }, + { + variant: 'other', + url: 'https://github.com/lorem-sum-dolor-amet-ipsiti-dolorum-ullrelle ', + }, + ], + } + + const methodTwo: MethodDataType = { + method_type: 'manual', + annotations_count: 1000, + method_description: + 'Vestibulum id ligula porta felis euismod semper. Maecenas sed diam eget risus varius blandit sit amet non magna.', + annotation_software: 'pyTOM + Keras', + links: [], + } + + const methodThree: MethodDataType = { + method_type: 'automated', + annotations_count: 6000, + method_description: + 'Cumulative template-matching trained 2D CNN predictions + visual filtering + distance constraints + manual addition', + annotation_software: 'pyTOM + Keras', + links: [ + { + variant: 'sourceCode', + title: 'My model’s source code', + url: 'https://example.com', + }, + { + variant: 'sourceCode', + title: 'Lorem-Ispum3-Dolor-V-2_5', + url: 'https://example.com', + }, + { + variant: 'modelWeights', + title: 'Model Weights for model Lorem-Ispum3-Dolor-V-2_5', + url: 'https://example.com', + }, + { + variant: 'website', + url: 'www.url.com', + }, + { + variant: 'documentation', + title: 'How to Use', + url: 'https://example.com', + }, + { + variant: 'other', + url: 'https://github.com/lorem-sum-dolor-amet-ipsiti-dolorum-ullrelle ', + }, + ], + } + + return ( + +
+ + + +
+
+ ) +} diff --git a/frontend/packages/data-portal/app/components/Deposition/AnnotationMethodsSummary.tsx b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksOverview.tsx similarity index 73% rename from frontend/packages/data-portal/app/components/Deposition/AnnotationMethodsSummary.tsx rename to frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksOverview.tsx index e5e532f49..ed2a83618 100644 --- a/frontend/packages/data-portal/app/components/Deposition/AnnotationMethodsSummary.tsx +++ b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/MethodLinksOverview.tsx @@ -1,9 +1,7 @@ import { Icon } from '@czi-sds/components' -import { ReactNode } from 'react' import { CollapsibleList } from 'app/components/CollapsibleList' import { I18n } from 'app/components/I18n' -import { SourceCodeIcon, WeightsIcon } from 'app/components/icons' import { Link } from 'app/components/Link' import { PageHeaderSubtitle } from 'app/components/PageHeaderSubtitle' import { Tooltip } from 'app/components/Tooltip' @@ -13,83 +11,12 @@ import { MethodType, } from 'app/constants/methodTypes' import { useI18n } from 'app/hooks/useI18n' -import { I18nKeys } from 'app/types/i18n' -interface MethodLink { - i18nLabel: I18nKeys - url: string - icon: ReactNode - title?: string -} - -const iconMap = { - sourceCode: ( - - ), - modelWeights: ( - - ), - website: ( - - ), - documentation: ( - - ), - other: ( - - ), -} as const - -interface MethodLinkVariantProps { - variant: keyof typeof iconMap - url: string - title?: string -} - -const variantOrder: (keyof typeof iconMap)[] = [ - 'sourceCode', - 'modelWeights', - 'website', - 'documentation', - 'other', -] - -function methodLinkFromVariant({ - variant, - url, - title, -}: MethodLinkVariantProps): MethodLink { - return { - i18nLabel: variant, - url, - title, - icon: iconMap[variant], - } -} - -function generateMethodLinks(links: MethodLinkVariantProps[]): MethodLink[] { - return links - .toSorted( - (a, b) => - variantOrder.indexOf(a.variant) - variantOrder.indexOf(b.variant), - ) - .map((props) => methodLinkFromVariant(props)) -} +import { + generateMethodLinks, + MethodLink, + MethodLinkVariantProps, +} from './common' function MethodTypeSection({ methodType, @@ -150,11 +77,12 @@ function MethodTypeSection({ ) } -export function AnnotationMethodsSummary() { +export function MethodLinksOverview() { const { t } = useI18n() const separator =
+ // TODO: populate this with backend data when available const hybridMethodLinks: MethodLinkVariantProps[] = [ { variant: 'sourceCode', diff --git a/frontend/packages/data-portal/app/components/Deposition/MethodLinks/common.tsx b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/common.tsx new file mode 100644 index 000000000..4765fec8c --- /dev/null +++ b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/common.tsx @@ -0,0 +1,83 @@ +import { Icon } from '@czi-sds/components' +import { ReactNode } from 'react' + +import { SourceCodeIcon, WeightsIcon } from 'app/components/icons' +import { I18nKeys } from 'app/types/i18n' + +export interface MethodLink { + i18nLabel: I18nKeys + url: string + icon: ReactNode + title?: string +} + +export const iconMap = { + sourceCode: ( + + ), + modelWeights: ( + + ), + website: ( + + ), + documentation: ( + + ), + other: ( + + ), +} as const + +export interface MethodLinkVariantProps { + variant: keyof typeof iconMap + url: string + title?: string +} + +const variantOrder: (keyof typeof iconMap)[] = [ + 'sourceCode', + 'modelWeights', + 'website', + 'documentation', + 'other', +] + +function methodLinkFromVariant({ + variant, + url, + title, +}: MethodLinkVariantProps): MethodLink { + return { + i18nLabel: variant, + url, + title, + icon: iconMap[variant], + } +} + +export function generateMethodLinks( + links: MethodLinkVariantProps[], +): MethodLink[] { + return links + .toSorted( + (a, b) => + variantOrder.indexOf(a.variant) - variantOrder.indexOf(b.variant), + ) + .map((props) => methodLinkFromVariant(props)) +} diff --git a/frontend/packages/data-portal/app/components/Deposition/MethodLinks/index.ts b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/index.ts new file mode 100644 index 000000000..960e43797 --- /dev/null +++ b/frontend/packages/data-portal/app/components/Deposition/MethodLinks/index.ts @@ -0,0 +1,2 @@ +export * from './MethodLinksMetadataTable' +export * from './MethodLinksOverview' diff --git a/frontend/packages/data-portal/app/components/Deposition/index.ts b/frontend/packages/data-portal/app/components/Deposition/index.ts index e69de29bb..554f40988 100644 --- a/frontend/packages/data-portal/app/components/Deposition/index.ts +++ b/frontend/packages/data-portal/app/components/Deposition/index.ts @@ -0,0 +1 @@ +export * from './DepositionMetadataDrawer' diff --git a/frontend/packages/data-portal/app/components/Run/RunMetadataDrawer.tsx b/frontend/packages/data-portal/app/components/Run/RunMetadataDrawer.tsx index 846f82bd9..8a8ed516b 100644 --- a/frontend/packages/data-portal/app/components/Run/RunMetadataDrawer.tsx +++ b/frontend/packages/data-portal/app/components/Run/RunMetadataDrawer.tsx @@ -18,7 +18,7 @@ export function RunMetadataDrawer() { label={i18n.runDetails} > diff --git a/frontend/packages/data-portal/app/constants/objectShapeTypes.ts b/frontend/packages/data-portal/app/constants/objectShapeTypes.ts index aa29d97a8..e8d25120e 100644 --- a/frontend/packages/data-portal/app/constants/objectShapeTypes.ts +++ b/frontend/packages/data-portal/app/constants/objectShapeTypes.ts @@ -1,6 +1,18 @@ -export const shapeTypeToI18nKey = { +import { I18nKeys } from 'app/types/i18n' +import { ObjectShapeType } from 'app/types/shapeTypes' + +type ShapeTypeToI18nKeyMap = { [key in ObjectShapeType]: I18nKeys } + +export const shapeTypeToI18nKey: ShapeTypeToI18nKeyMap = { InstanceSegmentation: 'instanceSegmentation', OrientedPoint: 'orientedPoint', Point: 'point', SegmentationMask: 'segmentationMask', } + +export const shapeTypeToI18nKeyPlural: ShapeTypeToI18nKeyMap = { + InstanceSegmentation: 'instanceSegmentations', + OrientedPoint: 'orientedPoints', + Point: 'points', + SegmentationMask: 'segmentationMasks', +} diff --git a/frontend/packages/data-portal/app/routes/depositions.$id.tsx b/frontend/packages/data-portal/app/routes/depositions.$id.tsx index c94672b9f..d36e8ded0 100644 --- a/frontend/packages/data-portal/app/routes/depositions.$id.tsx +++ b/frontend/packages/data-portal/app/routes/depositions.$id.tsx @@ -7,6 +7,7 @@ import { useEffect } from 'react' import { Order_By } from 'app/__generated__/graphql' import { apolloClient } from 'app/apollo.server' import { DatasetFilter } from 'app/components/DatasetFilter' +import { DepositionMetadataDrawer } from 'app/components/Deposition' import { DatasetsTable } from 'app/components/Deposition/DatasetsTable' import { DepositionHeader } from 'app/components/Deposition/DepositionHeader' import { TablePageLayout } from 'app/components/TablePageLayout' @@ -103,6 +104,7 @@ export default function DepositionByIdPage() { countLabel: t('datasets'), }, ]} + drawers={} /> ) } diff --git a/frontend/packages/data-portal/app/types/shapeTypes.ts b/frontend/packages/data-portal/app/types/shapeTypes.ts new file mode 100644 index 000000000..4fac266d6 --- /dev/null +++ b/frontend/packages/data-portal/app/types/shapeTypes.ts @@ -0,0 +1,5 @@ +export type ObjectShapeType = + | 'InstanceSegmentation' + | 'OrientedPoint' + | 'Point' + | 'SegmentationMask' diff --git a/frontend/packages/data-portal/public/locales/en/translation.json b/frontend/packages/data-portal/public/locales/en/translation.json index 5cb686c95..ef4bb0fd8 100644 --- a/frontend/packages/data-portal/public/locales/en/translation.json +++ b/frontend/packages/data-portal/public/locales/en/translation.json @@ -21,6 +21,7 @@ "allDatasets": "All Datasets", "allDepositions": "All Depositions", "annotatedObjects": "Annotated Objects", + "annotatedOrganisms": "Annotated Organisms", "annotationAuthor": "Annotation Author", "annotationAuthors": "Annotation Authors", "annotationConfidence": "Annotation Confidence", @@ -33,6 +34,8 @@ "annotationOverview": "Annotation Overview", "annotationSoftware": "Annotation Software", "annotations": "Annotations", + "annotationsSummary": "Annotations Summary", + "annotationsTotal": "Annotations (Total)", "api": "API", "apiDocLink": "https://chanzuckerberg.github.io/cryoet-data-portal/cryoet_data_portal_docsite_quick_start.html", "apply": "Apply", @@ -106,6 +109,7 @@ "depositionAnnotationsOnly": "Deposition annotations only", "depositionData": "Deposition Data", "depositionDate": "Deposition Date", + "depositionDetails": "Deposition Details", "depositionId": "Deposition ID", "depositionName": "Deposition Name", "depositionOnly": "Deposition only", @@ -180,6 +184,7 @@ "includedContents": "Included Contents", "info": "Info", "instanceSegmentation": "Instance Segmentation", + "instanceSegmentations": "Instance Segmentations", "keyPhoto": "key photo", "landingHeaderImageAttribution": "Top Image: The inner workings of an algal cell as depicted with cryo-electron tomography, which aggregates multiple snapshots of a single piece of material. Visible are the Golgi apparatus (green and magenta), and vesicles (multi-colored circles). | Photo credit: Y. S. Bykkov et al./eLIFE (CC BY 4.0)", "landingHeaderTitle": "Open access to annotated cryoET tomograms", @@ -199,11 +204,14 @@ "meetsAll": "Meets all", "metadata": "Metadata", "methodLinks": "Method Links", + "methodThree": "Method Three", + "methodTwo": "Method Two", "methodType": "Method Type", "methodTypeAutomated": "Automated: Annotations were generated using automated tools or algorithms without supervision.", "methodTypeHybrid": "Hybrid: Annotations were generated using a combination of automated and manual methods.", "methodTypeInfo": "Method Type: Describes how the annotations were generated.", "methodTypeManual": "Manual: Annotations were created by hand.", + "methodOne": "Method One", "microscopeManufacturer": "Microscope Manufacturer", "microscopeModel": "Microscope model", "modelWeights": "Model Weights", @@ -222,11 +230,13 @@ "normalText": "Normal text", "notApplicable": "Not Applicable", "notSubmitted": "Not Submitted", + "numberOfAnnotations": "Number of Annotations", "numberOfRuns": "Number of Runs", "objectCount": "Object Count", "objectDescription": "Object Description", "objectName": "Object Name", "objectShapeType": "Object Shape Type", + "objectShapeTypes": "Object Shape Types", "objectState": "Object State", "openDataset": "Open Dataset", "openDeposition": "Open Deposition", @@ -238,6 +248,7 @@ "organismName": "Organism Name", "organizers": "Organizers", "orientedPoint": "Oriented Point", + "orientedPoints": "Oriented Points", "other": "Other", "otherAnnotations_one": "{{count}} Other Annotation", "otherAnnotations_other": "{{count}} Other Annotations", @@ -248,6 +259,7 @@ "pixelSpacing": "Pixel Spacing", "plusMore": "+{{count}} More", "point": "Point", + "points": "Points", "poor": "Poor", "postProcessing": "Post Processing", "precision": "Precision", @@ -290,13 +302,15 @@ "sampleType": "Sample Type", "search": "Search", "segmentationMask": "Segmentation Mask", + "segmentationMasks": "Segmentation Masks", "selectASpecificTomogram": "Select a specific tomogram from this run to download.", "selectDownload": "Select Download", "selectDownloadMethod": "Select Download Method", "selectSaveDestination": "Select Save Destination", "seriesIsAligned": "Series is Aligned", "showLess": "Show less", - "showMore": "Show {{count}} more", + "showMore": "Show more", + "showNumberMore": "Show {{count}} more", "size": "Size", "smallestAvailableVoxelSpacing": "Smallest Available Voxel Spacing", "somethingWentWrong": "Something went wrong",