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 (
+
+ )
+}
+
+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",