diff --git a/frontend/packages/data-portal/app/components/BrowseData/DatasetTable.tsx b/frontend/packages/data-portal/app/components/BrowseData/DatasetTable.tsx index bd7e28bf2..a132bd201 100644 --- a/frontend/packages/data-portal/app/components/BrowseData/DatasetTable.tsx +++ b/frontend/packages/data-portal/app/components/BrowseData/DatasetTable.tsx @@ -16,6 +16,7 @@ import { ComponentProps, ReactNode } from 'react' import { GetDatasetsDataQuery } from 'app/__generated__/graphql' import { Link } from 'app/components/Link' import { TableCell } from 'app/components/TableCell' +import { EMPIAR_ID } from 'app/constants/external-dbs' import { MAX_PER_PAGE } from 'app/constants/pagination' import { useIsLoading } from 'app/hooks/useIsLoading' import { i18n } from 'app/i18n' @@ -151,7 +152,7 @@ export function DatasetTable() { {datasets.map((dataset) => { - const empiarIDMatch = /EMPIAR-([\d]+)/.exec( + const empiarIDMatch = EMPIAR_ID.exec( dataset.dataset_publications ?? '', ) const empiarID = empiarIDMatch?.[1] diff --git a/frontend/packages/data-portal/app/components/Dataset/DatasetDescription.tsx b/frontend/packages/data-portal/app/components/Dataset/DatasetDescription.tsx new file mode 100644 index 000000000..b70aa13cb --- /dev/null +++ b/frontend/packages/data-portal/app/components/Dataset/DatasetDescription.tsx @@ -0,0 +1,206 @@ +import { Button } from '@czi-sds/components' +import clsx from 'clsx' +import { useState } from 'react' + +import { EnvelopeIcon } from 'app/components/icons' +import { Link } from 'app/components/Link' +import { + DatabaseType, + DOI_ID, + LABEL_MAP, + REGEX_MAP, + URL_MAP, +} from 'app/constants/external-dbs' +import { useDatasetById } from 'app/hooks/useDatasetById' +import { i18n } from 'app/i18n' + +// use clsx here instead of cns since it erroneously merges text-sds-gray-500 and text-sds-caps-xxxs +const sectionHeaderStyles = clsx( + 'font-semibold uppercase', + 'text-sds-gray-500', + 'text-sds-caps-xxxs leading-sds-caps-xxxs tracking-sds-caps', +) + +interface DatabaseEntryProps { + entry: string +} + +function DatabaseEntry(props: DatabaseEntryProps) { + const { entry } = props + let dbtype: DatabaseType | undefined + let id: string = '' + + for (const [dbt, pattern] of REGEX_MAP) { + const match = pattern.exec(entry) + if (match !== null) { + dbtype = dbt + // eslint-disable-next-line prefer-destructuring + id = match[1] + break + } + } + + if (dbtype === undefined) { + return

{entry}

+ } + + return ( +

+ + {LABEL_MAP.get(dbtype)}: + + + {entry} + +

+ ) +} + +interface DatabaseListProps { + title: string + entries?: string[] + className?: string + collapseAfter?: number +} + +function DatabaseList(props: DatabaseListProps) { + const { title, entries, className, collapseAfter } = props + const collapsible = + collapseAfter !== undefined && + collapseAfter >= 0 && + entries !== undefined && + entries.length > collapseAfter + const [collapsed, setCollapsed] = useState(true) + + return ( +
+

{title}

+ {entries ? ( + + ) : ( +

+ {i18n.notSubmitted} +

+ )} +
+ ) +} + +export function DatasetDescription() { + const { dataset } = useDatasetById() + + // TODO: make the below grouping more efficient and/or use GraphQL ordering + const authorsPrimary = dataset.authors.filter( + (author) => author.primary_author_status, + ) + const authorsCorresponding = dataset.authors.filter( + (author) => author.corresponding_author_status, + ) + const authorsOther = dataset.authors.filter( + (author) => + !(author.primary_author_status || author.corresponding_author_status), + ) + + // clean up entries into lists + const publicationEntries = dataset.dataset_publications + ?.split(',') + .map((e) => e.trim()) + .filter((e) => DOI_ID.exec(e)) // only show DOI links + + const relatedDatabaseEntries = dataset.related_database_entries + ?.split(',') + .map((e) => e.trim()) + + const envelopeIcon = ( + + ) + + return ( +
+

+ {dataset.description} +

+
+

{i18n.authors}

+ {/* TODO: let's find a better way of doing this */} +

+ + {authorsPrimary.map((author, i, arr) => ( + <> + {author.name} + {!( + authorsOther.length + authorsCorresponding.length === 0 && + arr.length - 1 === i + ) && '; '} + + ))} + + + {authorsOther.map((author, i, arr) => ( + <> + {author.name} + {!(authorsCorresponding.length === 0 && arr.length - 1 === i) && + '; '} + + ))} + {authorsCorresponding.map((author, i, arr) => ( + <> + {author.name} + {author.email ? ( + {envelopeIcon} + ) : ( + envelopeIcon + )} + {!(arr.length - 1 === i) && '; '} + + ))} + +

+
+
+ + + {/* extra div to turn it into 3 columns */} +
+
+
+ ) +} diff --git a/frontend/packages/data-portal/app/components/Dataset/DatasetHeader.tsx b/frontend/packages/data-portal/app/components/Dataset/DatasetHeader.tsx index f87731de6..3e22e7c80 100644 --- a/frontend/packages/data-portal/app/components/Dataset/DatasetHeader.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/DatasetHeader.tsx @@ -1,48 +1,111 @@ -import { Icon } from '@czi-sds/components' +import { Button, Icon } from '@czi-sds/components' import { useSearchParams } from '@remix-run/react' +import { DatasetDescription } from 'app/components/Dataset/DatasetDescription' import { Link } from 'app/components/Link' import { useDatasetById } from 'app/hooks/useDatasetById' import { i18n } from 'app/i18n' +import { useDatasetDrawer } from 'app/state/drawer' import { cns } from 'app/utils/cns' export function DatasetHeader() { const [params] = useSearchParams() const previousUrl = params.get('prev') - const dataset = useDatasetById() + const { dataset } = useDatasetById() + const drawer = useDatasetDrawer() return ( -
-
- {previousUrl && ( - - - - Back to results - - - )} +
+
+
+ {/* back button */} + {previousUrl && ( +
+ + + + Back to Results + + +
+ )} +
+ {/* dataset title */} +

+ {dataset.title} +

+ {/* portal ID */} +
+

+ {i18n.portalIdBlank} +

+

{dataset.id}

+
+
-
-

{i18n.releaseDate(dataset.release_date)}

-
-

- {i18n.lastModified( - dataset.last_modified_date ?? dataset.deposition_date, + {/* dates */} +

+ > +

{i18n.releaseDate(dataset.release_date)}

+
+

+ {i18n.lastModified( + dataset.last_modified_date ?? dataset.deposition_date, + )} +

+
+ + {/* actions */} +
+ + +
+
+
+ + {/* add key photo here */}
diff --git a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx index 8d64592a6..8b6ab5300 100644 --- a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataDrawer.tsx @@ -34,7 +34,7 @@ const ACTIVE_TAB_PARAM = 'tab' export function DatasetMetadataDrawer() { const drawer = useDatasetDrawer() - const dataset = useDatasetById() + const { dataset } = useDatasetById() const [searchParams, setSearchParams] = useSearchParams() const activeTab = (searchParams.get(ACTIVE_TAB_PARAM) ?? diff --git a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx index 4dd9e1851..bf82b1217 100644 --- a/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/DatasetMetadataTable.tsx @@ -5,7 +5,7 @@ import { AccordionMetadataTable } from './AccordionMetadataTable' import { getTableData } from './utils' export function DatasetMetadataTable() { - const dataset = useDatasetById() + const { dataset } = useDatasetById() const datasetMetadata = getTableData( { label: i18n.depositionDate, @@ -13,7 +13,7 @@ export function DatasetMetadataTable() { }, { label: i18n.affiliationName, - values: dataset.authors + values: dataset.authors_with_affiliation .map((author) => author.affiliation_name) .filter((value): value is string => !!value), }, diff --git a/frontend/packages/data-portal/app/components/Dataset/SampleAndExperimentConditionsTable.tsx b/frontend/packages/data-portal/app/components/Dataset/SampleAndExperimentConditionsTable.tsx index cfe723a8f..9e30a0a13 100644 --- a/frontend/packages/data-portal/app/components/Dataset/SampleAndExperimentConditionsTable.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/SampleAndExperimentConditionsTable.tsx @@ -5,7 +5,7 @@ import { AccordionMetadataTable } from './AccordionMetadataTable' import { getTableData } from './utils' export function SampleAndExperimentConditionsTable() { - const dataset = useDatasetById() + const { dataset } = useDatasetById() const sampleAndExperimentConditions = getTableData( { diff --git a/frontend/packages/data-portal/app/components/Dataset/TiltSeriesTable.tsx b/frontend/packages/data-portal/app/components/Dataset/TiltSeriesTable.tsx index 8756bebf0..5cdffeece 100644 --- a/frontend/packages/data-portal/app/components/Dataset/TiltSeriesTable.tsx +++ b/frontend/packages/data-portal/app/components/Dataset/TiltSeriesTable.tsx @@ -5,7 +5,7 @@ import { AccordionMetadataTable } from './AccordionMetadataTable' import { getTableData } from './utils' export function TiltSeriesTable() { - const dataset = useDatasetById() + const { dataset } = useDatasetById() const tiltSeriesData = dataset.runs[0]?.tiltseries[0] const tiltSeries = tiltSeriesData diff --git a/frontend/packages/data-portal/app/components/Layout/TopNavigation.tsx b/frontend/packages/data-portal/app/components/Layout/TopNavigation.tsx index d59768222..485e6fcdd 100644 --- a/frontend/packages/data-portal/app/components/Layout/TopNavigation.tsx +++ b/frontend/packages/data-portal/app/components/Layout/TopNavigation.tsx @@ -15,7 +15,7 @@ export function TopNavigation() {