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 };