diff --git a/CHANGELOG-cat-435.md b/CHANGELOG-cat-435.md new file mode 100644 index 0000000000..d5494f0778 --- /dev/null +++ b/CHANGELOG-cat-435.md @@ -0,0 +1 @@ +- Avoid page scrolling from using arrow keys on vitessce visualization. diff --git a/CHANGELOG-cat-751.md b/CHANGELOG-cat-751.md new file mode 100644 index 0000000000..35331d958e --- /dev/null +++ b/CHANGELOG-cat-751.md @@ -0,0 +1 @@ +- Prevent malformed provenance graph data from crashing the entire page. diff --git a/CHANGELOG-update-hive-group.md b/CHANGELOG-update-hive-group.md new file mode 100644 index 0000000000..e8215849fe --- /dev/null +++ b/CHANGELOG-update-hive-group.md @@ -0,0 +1 @@ +- Update group for HIVE-processed datasets to be 'HIVE'. \ No newline at end of file diff --git a/context/app/static/js/components/detailPage/MetadataTable/MetadataTable.tsx b/context/app/static/js/components/detailPage/MetadataTable/MetadataTable.tsx index 2291ff3b56..5bb3992ccb 100644 --- a/context/app/static/js/components/detailPage/MetadataTable/MetadataTable.tsx +++ b/context/app/static/js/components/detailPage/MetadataTable/MetadataTable.tsx @@ -5,7 +5,6 @@ import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; -import Stack from '@mui/material/Stack'; import { StyledTableContainer, HeaderCell } from 'js/shared-styles/tables'; import IconTooltipCell from 'js/shared-styles/tables/IconTooltipCell'; @@ -35,10 +34,11 @@ function MetadataTable({ tableRows = [] as MetadataTableRow[], columns = default {row.key} - - {row.value} - {row.key.endsWith('age_value') && } - + {row.key.endsWith('age_value') ? ( + {row.value} + ) : ( + row.value + )} ))} diff --git a/context/app/static/js/components/detailPage/ProcessedData/ProcessedDataset/ProcessedDataset.tsx b/context/app/static/js/components/detailPage/ProcessedData/ProcessedDataset/ProcessedDataset.tsx index 757fdce06d..e324ed13b4 100644 --- a/context/app/static/js/components/detailPage/ProcessedData/ProcessedDataset/ProcessedDataset.tsx +++ b/context/app/static/js/components/detailPage/ProcessedData/ProcessedDataset/ProcessedDataset.tsx @@ -26,6 +26,7 @@ import { getDateLabelAndValue } from 'js/components/detailPage/utils'; import { useSelectedVersionStore } from 'js/components/detailPage/VersionSelect/SelectedVersionStore'; import { useVersions } from 'js/components/detailPage/VersionSelect/hooks'; import { useTrackEntityPageEvent } from 'js/components/detailPage/useTrackEntityPageEvent'; +import InfoTextTooltip from 'js/shared-styles/tooltips/InfoTextTooltip'; import { DatasetTitle } from './DatasetTitle'; import { ProcessedDatasetAccordion } from './ProcessedDatasetAccordion'; @@ -70,13 +71,23 @@ function Contact() { function SummaryAccordion() { const { dataset } = useProcessedDatasetContext(); + const { group_name, mapped_consortium, creation_action } = dataset; const [dateLabel, dateValue] = getDateLabelAndValue(dataset); + + const isHiveProcessed = creation_action === 'Central Process'; + return ( }> - {dataset.group_name} - {dataset.mapped_consortium} + + {isHiveProcessed ? ( + HIVE + ) : ( + group_name + )} + + {mapped_consortium} {dateValue ? formatDate(new Date(dateValue), 'yyyy-MM-dd') : 'N/A'} diff --git a/context/app/static/js/components/detailPage/entityHeader/EntityHeaderContent/EntityHeaderContent.tsx b/context/app/static/js/components/detailPage/entityHeader/EntityHeaderContent/EntityHeaderContent.tsx index 23bb92a5ca..9d38915dc7 100644 --- a/context/app/static/js/components/detailPage/entityHeader/EntityHeaderContent/EntityHeaderContent.tsx +++ b/context/app/static/js/components/detailPage/entityHeader/EntityHeaderContent/EntityHeaderContent.tsx @@ -73,10 +73,9 @@ function DonorItems({ data: { entity } }: EntityHeaderItemsProps) { {race && {race}} {age_unit && age_value && ( - + {age_value} {age_unit} - - + )} diff --git a/context/app/static/js/components/detailPage/provenance/ProvGraph/ProvGraphErrorBoundary.tsx b/context/app/static/js/components/detailPage/provenance/ProvGraph/ProvGraphErrorBoundary.tsx new file mode 100644 index 0000000000..3739826c0a --- /dev/null +++ b/context/app/static/js/components/detailPage/provenance/ProvGraph/ProvGraphErrorBoundary.tsx @@ -0,0 +1,24 @@ +import { FaroErrorBoundary } from '@grafana/faro-react'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import DetailsAccordion from 'js/shared-styles/accordions/DetailsAccordion'; +import React from 'react'; + +interface ErrorBoundaryProps { + children: React.ReactNode; +} + +function ErrorFallback(error: Error) { + return ( + + An error occurred while attempting to display the provenance graph. + + {error?.message} + + + ); +} + +export default function ProvGraphErrorBoundary({ children }: ErrorBoundaryProps) { + return {children}; +} diff --git a/context/app/static/js/components/detailPage/provenance/ProvSection/ProvSection.tsx b/context/app/static/js/components/detailPage/provenance/ProvSection/ProvSection.tsx index b012b49124..b4c3589ab2 100644 --- a/context/app/static/js/components/detailPage/provenance/ProvSection/ProvSection.tsx +++ b/context/app/static/js/components/detailPage/provenance/ProvSection/ProvSection.tsx @@ -83,6 +83,7 @@ function ProvSection() { + ); diff --git a/context/app/static/js/components/detailPage/provenance/ProvTabs/ProvTabs.tsx b/context/app/static/js/components/detailPage/provenance/ProvTabs/ProvTabs.tsx index 7e630f6189..6fa6550b41 100644 --- a/context/app/static/js/components/detailPage/provenance/ProvTabs/ProvTabs.tsx +++ b/context/app/static/js/components/detailPage/provenance/ProvTabs/ProvTabs.tsx @@ -9,6 +9,7 @@ import ProvTable from '../ProvTable'; import { hasDataTypes } from './utils'; import { filterTabsToDisplay } from './filterTabsToDisplay'; import { ProvData } from '../types'; +import ProvGraphErrorBoundary from '../ProvGraph/ProvGraphErrorBoundary'; const availableTabDetails = { multi: { label: 'Multi-Assay', 'data-testid': 'multi-prov-tab' }, @@ -67,7 +68,9 @@ function ProvTabs({ provData }: ProvTabsProps) { )} {filteredTabs?.graph && ( - + + + )} diff --git a/context/app/static/js/components/detailPage/visualization/VisualizationTracker/hooks.ts b/context/app/static/js/components/detailPage/visualization/VisualizationTracker/hooks.ts index 3685a128a2..cdf7547dab 100644 --- a/context/app/static/js/components/detailPage/visualization/VisualizationTracker/hooks.ts +++ b/context/app/static/js/components/detailPage/visualization/VisualizationTracker/hooks.ts @@ -32,6 +32,8 @@ export function useVitessceEventMetadata() { return formatEventCategoryAndLabel('Unknown', location); } +const arrowKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']; + export function useVisualizationTracker() { const { category, label } = useVitessceEventMetadata(); // Track when the visualization is first mounted @@ -66,6 +68,11 @@ export function useVisualizationTracker() { const trackKeyDown: React.KeyboardEventHandler = useEventCallback((e) => { const target = getNearestIdentifier(e.target as HTMLElement); const key = e.key === ' ' ? 'Space' : e.key; + // Prevent default scrolling behavior of arrow keys + if (arrowKeys.includes(key)) { + trackVitessceAction(`${key} ${target}`); + e.preventDefault(); + } if (!target || modifierKeys.includes(key)) return; if (typingTimeout.current) { clearTimeout(typingTimeout.current); diff --git a/context/app/static/js/components/entity-tile/EntityTileBody/EntityTileBody.tsx b/context/app/static/js/components/entity-tile/EntityTileBody/EntityTileBody.tsx index 3fa0d02c65..32c80e94a9 100644 --- a/context/app/static/js/components/entity-tile/EntityTileBody/EntityTileBody.tsx +++ b/context/app/static/js/components/entity-tile/EntityTileBody/EntityTileBody.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import Stack from '@mui/system/Stack'; import Tile from 'js/shared-styles/tiles/Tile'; import EntityTileThumbnail from 'js/components/entity-tile/EntityTileThumbnail'; import { getOriginSamplesOrgan } from 'js/helpers/functions'; @@ -35,10 +34,9 @@ function EntityTileBody({ entity_type, id, entityData, invertColors }: EntityTil {entityData.mapped_metadata?.sex} - + {entityData.mapped_metadata?.age_value} {entityData.mapped_metadata?.age_unit} - - + {(entityData.mapped_metadata?.race ?? []).join(', ')} diff --git a/context/app/static/js/components/searchPage/ResultsTable/utils.jsx b/context/app/static/js/components/searchPage/ResultsTable/utils.jsx index b7ba8105db..d89b6ca3b6 100644 --- a/context/app/static/js/components/searchPage/ResultsTable/utils.jsx +++ b/context/app/static/js/components/searchPage/ResultsTable/utils.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import Stack from '@mui/material/Stack'; import { get } from 'js/helpers/nodash'; import DonorAgeTooltip from 'js/shared-styles/tooltips/DonorAgeTooltip'; @@ -53,10 +52,7 @@ function getByPath(hitSource, field) { if (Array.isArray(fieldValue)) { if (field?.id === 'mapped_metadata.age_value') { return ( - - {fieldValue.join(' / ')} - {fieldValue.length > 0 && } - + fieldValue.length > 0 && {fieldValue.join(' / ')} ); } return fieldValue.join(' / '); diff --git a/context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/DonorAgeTooltip.tsx b/context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/DonorAgeTooltip.tsx index 5b386abcb6..8f2b86d231 100644 --- a/context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/DonorAgeTooltip.tsx +++ b/context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/DonorAgeTooltip.tsx @@ -1,25 +1,17 @@ -import React from 'react'; - -import { SecondaryBackgroundTooltip } from 'js/shared-styles/tooltips'; -import { StyledStack, StyledInfoIcon } from 'js/shared-styles/tooltips/DonorAgeTooltip/style'; +import React, { PropsWithChildren } from 'react'; +import InfoTextTooltip from 'js/shared-styles/tooltips/InfoTextTooltip'; const DONOR_AGE_TEXT = 'For donors older than 89, the metadata will indicate an age of 90.'; -interface DonorAgeTooltipProps { +interface DonorAgeTooltipProps extends PropsWithChildren { donorAge?: string; } -function DonorAgeTooltip({ donorAge }: DonorAgeTooltipProps) { +function DonorAgeTooltip({ donorAge, children }: DonorAgeTooltipProps) { if (!donorAge || Number(donorAge) <= 89) { - return null; + return children; } - return ( - - - - - - ); + return {children}; } export default DonorAgeTooltip; diff --git a/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/InfoTextTooltip.tsx b/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/InfoTextTooltip.tsx new file mode 100644 index 0000000000..ba161daf28 --- /dev/null +++ b/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/InfoTextTooltip.tsx @@ -0,0 +1,22 @@ +import React, { PropsWithChildren } from 'react'; + +import { SecondaryBackgroundTooltip } from 'js/shared-styles/tooltips'; +import { StyledInfoIcon, StyledOuterStack, StyledInnerStack } from 'js/shared-styles/tooltips/InfoTextTooltip/style'; + +interface InfoTextTooltipProps extends PropsWithChildren { + tooltipTitle: string; +} + +function InfoTextTooltip({ tooltipTitle, children }: InfoTextTooltipProps) { + return ( + + {children} + + + + + + + ); +} +export default InfoTextTooltip; diff --git a/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/index.ts b/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/index.ts new file mode 100644 index 0000000000..19616205d0 --- /dev/null +++ b/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/index.ts @@ -0,0 +1,3 @@ +import InfoTextTooltip from './InfoTextTooltip'; + +export default InfoTextTooltip; diff --git a/context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/style.ts b/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/style.ts similarity index 60% rename from context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/style.ts rename to context/app/static/js/shared-styles/tooltips/InfoTextTooltip/style.ts index ce7bf6c6bc..fe84b716ee 100644 --- a/context/app/static/js/shared-styles/tooltips/DonorAgeTooltip/style.ts +++ b/context/app/static/js/shared-styles/tooltips/InfoTextTooltip/style.ts @@ -2,7 +2,12 @@ import { Stack } from '@mui/material'; import { styled } from '@mui/material/styles'; import { InfoIcon } from 'js/shared-styles/icons'; -const StyledStack = styled(Stack)(({ theme }) => ({ +const StyledOuterStack = styled(Stack)({ + alignItems: 'center', + flexDirection: 'row', +}); + +const StyledInnerStack = styled(Stack)(({ theme }) => ({ marginLeft: theme.spacing(0.5), justifyContent: 'center', })); @@ -12,4 +17,4 @@ const StyledInfoIcon = styled(InfoIcon)(({ theme }) => ({ fontSize: '0.75rem', })); -export { StyledStack, StyledInfoIcon }; +export { StyledOuterStack, StyledInnerStack, StyledInfoIcon };