From ca47741921ac8c666929ace1aa6bf0b8b04bece9 Mon Sep 17 00:00:00 2001 From: BrandonAndre Date: Tue, 14 Jan 2025 14:56:24 -0500 Subject: [PATCH] Support #35538 - Molecular Analysis Run view page bug and test coverage - Moved the 2 hooks inside useMolecularAnalysRun to their own hooks. - Updated imports. --- .../MolecularAnalysisRunFormFields.tsx | 8 +- ...tagenomicsWorkflowMolecularAnalysisRun.tsx | 4 +- .../useMolecularAnalysisRun.tsx | 860 +----------------- .../useMolecularAnalysisRunColumns.tsx | 610 +++++++++++++ .../useMolecularAnalysisRunView.tsx | 255 ++++++ 5 files changed, 879 insertions(+), 858 deletions(-) create mode 100644 packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunColumns.tsx create mode 100644 packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunView.tsx diff --git a/packages/dina-ui/components/molecular-analysis/MolecularAnalysisRunFormFields.tsx b/packages/dina-ui/components/molecular-analysis/MolecularAnalysisRunFormFields.tsx index 360d8e043..39ba6f7c6 100644 --- a/packages/dina-ui/components/molecular-analysis/MolecularAnalysisRunFormFields.tsx +++ b/packages/dina-ui/components/molecular-analysis/MolecularAnalysisRunFormFields.tsx @@ -8,15 +8,14 @@ import { DinaMessage, useDinaIntl } from "../../intl/dina-ui-intl"; import { GroupSelectField } from "../group-select/GroupSelectField"; import { AttachmentReadOnlySection } from "../object-store/attachment-list/AttachmentReadOnlySection"; import { QualityControlSection } from "../seqdb/molecular-analysis-workflow/QualityControlSection"; -import { - SequencingRunItem, - useMolecularAnalysisRunView -} from "./useMolecularAnalysisRun"; +import { SequencingRunItem } from "./useMolecularAnalysisRun"; import { SeqdbMessage } from "../../intl/seqdb-intl"; +import { useMolecularAnalysisRunView } from "./useMolecularAnalysisRunView"; export function MolecularAnalysisRunFormFields() { const { initialValues } = useDinaFormContext(); const { formatMessage } = useDinaIntl(); + const { loading, sequencingRunItems, @@ -26,6 +25,7 @@ export function MolecularAnalysisRunFormFields() { } = useMolecularAnalysisRunView({ molecularAnalysisRunId: initialValues.id }); + return loading ? ( ) : ( diff --git a/packages/dina-ui/components/molecular-analysis/useMetagenomicsWorkflowMolecularAnalysisRun.tsx b/packages/dina-ui/components/molecular-analysis/useMetagenomicsWorkflowMolecularAnalysisRun.tsx index 972ee3e6c..d9454c689 100644 --- a/packages/dina-ui/components/molecular-analysis/useMetagenomicsWorkflowMolecularAnalysisRun.tsx +++ b/packages/dina-ui/components/molecular-analysis/useMetagenomicsWorkflowMolecularAnalysisRun.tsx @@ -1,4 +1,4 @@ -import { PcrBatchItem, SeqReaction } from "../../types/seqdb-api"; +import { PcrBatchItem } from "../../types/seqdb-api"; import { MolecularAnalysisRunItem } from "../../types/seqdb-api/resources/molecular-analysis/MolecularAnalysisRunItem"; import { useEffect, useState } from "react"; import { @@ -16,7 +16,7 @@ import { useDinaIntl } from "../../intl/dina-ui-intl"; import { ColumnDef } from "@tanstack/react-table"; import { MetagenomicsBatchItem } from "packages/dina-ui/types/seqdb-api/resources/metagenomics/MetagenomicsBatchItem"; import { MetagenomicsBatch } from "packages/dina-ui/types/seqdb-api/resources/metagenomics/MetagenomicsBatch"; -import { useMolecularAnalysisRunColumns } from "./useMolecularAnalysisRun"; +import { useMolecularAnalysisRunColumns } from "./useMolecularAnalysisRunColumns"; export interface UseMetagenomicsWorkflowMolecularAnalysisRunProps { metagenomicsBatchId: string; diff --git a/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRun.tsx b/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRun.tsx index 10d146460..90adc6395 100644 --- a/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRun.tsx +++ b/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRun.tsx @@ -1,48 +1,21 @@ import { PcrBatchItem, SeqReaction } from "../../types/seqdb-api"; -import { - ChangeEvent, - Dispatch, - SetStateAction, - useEffect, - useMemo, - useState -} from "react"; +import { useEffect, useMemo, useState } from "react"; import { BulkGetOptions, - DeleteArgs, - FieldHeader, filterBy, SaveArgs, - SettingsButton, - useAccount, useApiClient, - useQuery, - useStringComparator + useQuery } from "common-ui"; import { StorageUnitUsage } from "../../types/collection-api/resources/StorageUnitUsage"; import { KitsuResource, PersistedResource } from "kitsu"; import { MaterialSampleSummary } from "../../types/collection-api"; -import { DinaMessage, useDinaIntl } from "../../intl/dina-ui-intl"; +import { useDinaIntl } from "../../intl/dina-ui-intl"; import { ColumnDef } from "@tanstack/react-table"; -import Link from "next/link"; -import { attachGenericMolecularAnalysisItems } from "../seqdb/molecular-analysis-workflow/useGenericMolecularAnalysisRun"; -import { GenericMolecularAnalysisItem } from "packages/dina-ui/types/seqdb-api/resources/GenericMolecularAnalysisItem"; import { MolecularAnalysisRunItem } from "packages/dina-ui/types/seqdb-api/resources/molecular-analysis/MolecularAnalysisRunItem"; import { MolecularAnalysisRun } from "packages/dina-ui/types/seqdb-api/resources/molecular-analysis/MolecularAnalysisRun"; import { ResourceIdentifierObject } from "jsonapi-typescript"; -import { MetagenomicsBatchItem } from "packages/dina-ui/types/seqdb-api/resources/metagenomics/MetagenomicsBatchItem"; -import { - attachMaterialSampleSummaryMetagenomics, - attachMetagenomicsBatchItem, - attachPcrBatchItemMetagenomics, - attachStorageUnitUsageMetagenomics -} from "./useMetagenomicsWorkflowMolecularAnalysisRun"; -import { QualityControl } from "packages/dina-ui/types/seqdb-api/resources/QualityControl"; -import useVocabularyOptions from "../collection/useVocabularyOptions"; -import { AddAttachmentsButton } from "../object-store"; -import { MolecularAnalysisResult } from "packages/dina-ui/types/seqdb-api/resources/molecular-analysis/MolecularAnalysisResult"; -import { Metadata } from "packages/dina-ui/types/objectstore-api"; -import React from "react"; +import { useMolecularAnalysisRunColumns } from "./useMolecularAnalysisRunColumns"; export interface UseMolecularAnalysisRunProps { seqBatchId: string; @@ -136,7 +109,7 @@ export interface UseMolecularAnalysisRunReturn { * @param seqReaction * @returns The initial structure of SequencingRunItem. */ -function attachSeqReaction( +export function attachSeqReaction( seqReaction: PersistedResource[] ): SequencingRunItem[] { return seqReaction.map((reaction) => { @@ -158,7 +131,7 @@ function attachSeqReaction( * to retrieve the full storage unit since it's stored in the collection-api. * @returns The updated SeqReactionSample with storage unit attached. */ -async function attachStorageUnitUsage( +export async function attachStorageUnitUsage( sequencingRunItem: SequencingRunItem[], bulkGet: ( paths: readonly string[], @@ -190,7 +163,7 @@ async function attachStorageUnitUsage( /** * Fetch MaterialSampleSummary from each PcrBatchItem. */ -async function attachMaterialSampleSummary( +export async function attachMaterialSampleSummary( sequencingRunItem: SequencingRunItem[], bulkGet: ( paths: readonly string[], @@ -222,7 +195,7 @@ async function attachMaterialSampleSummary( /** * Fetch PcrBatchItem linked to each SeqReactions. */ -async function attachPcrBatchItem( +export async function attachPcrBatchItem( sequencingRunItem: SequencingRunItem[], bulkGet: ( paths: readonly string[], @@ -648,820 +621,3 @@ export function useMolecularAnalysisRun({ sequencingRunId: sequencingRun?.id }; } - -export interface UseMolecularAnalysisRunViewProps { - molecularAnalysisRunId: string; -} -export function useMolecularAnalysisRunView({ - molecularAnalysisRunId -}: UseMolecularAnalysisRunViewProps) { - const { apiClient, bulkGet } = useApiClient(); - const [columns, setColumns] = useState([]); - // Run Items - const [sequencingRunItems, setSequencingRunItems] = - useState(); - const [loading, setLoading] = useState(true); - const { compareByStringAndNumber } = useStringComparator(); - - // Quality control items - const [qualityControls, setQualityControls] = useState([]); - const { loading: loadingVocabularyItems, vocabOptions: qualityControlTypes } = - useVocabularyOptions({ - path: "seqdb-api/vocabulary/qualityControlType" - }); - const molecularAnalysisRunItemQuery = useQuery( - { - path: `seqdb-api/molecular-analysis-run-item`, - filter: filterBy([], { - extraFilters: [ - { - selector: "run.uuid", - comparison: "==", - arguments: molecularAnalysisRunId - } - ] - })("") - }, - { - onSuccess: async ({ data: molecularAnalysisRunItems }) => { - async function fetchSeqReactions() { - const fetchPaths = molecularAnalysisRunItems.map( - (molecularAnalysisRunItem) => - `seqdb-api/seq-reaction?include=storageUnitUsage,pcrBatchItem,seqPrimer&filter[rsql]=molecularAnalysisRunItem.uuid==${molecularAnalysisRunItem.id}` - ); - const seqReactions: PersistedResource[] = []; - for (const path of fetchPaths) { - const seqReaction = await apiClient.get(path, {}); - seqReactions.push(seqReaction.data[0]); - } - return seqReactions; - } - - async function fetchGenericMolecularAnalysisItems() { - const fetchPaths = molecularAnalysisRunItems - .filter((runItem) => runItem.usageType !== "quality-control") - .map( - (molecularAnalysisRunItem) => - `seqdb-api/generic-molecular-analysis-item?include=storageUnitUsage,materialSample,molecularAnalysisRunItem&filter[rsql]=molecularAnalysisRunItem.uuid==${molecularAnalysisRunItem.id}` - ); - const genericMolecularAnalysisItems: PersistedResource[] = - []; - for (const path of fetchPaths) { - const genericMolecularAnalysisItem = await apiClient.get< - GenericMolecularAnalysisItem[] - >(path, {}); - genericMolecularAnalysisItems.push( - genericMolecularAnalysisItem.data[0] - ); - } - return genericMolecularAnalysisItems; - } - - async function fetchMetagenomicsBatchItems() { - const fetchPaths = molecularAnalysisRunItems.map( - (molecularAnalysisRunItem) => - `seqdb-api/metagenomics-batch-item?include=pcrBatchItem&filter[rsql]=molecularAnalysisRunItem.uuid==${molecularAnalysisRunItem.id}` - ); - const metagenomicsBatchItems: PersistedResource[] = - []; - for (const path of fetchPaths) { - const metagenomicsBatchItem = await apiClient.get< - MetagenomicsBatchItem[] - >(path, {}); - metagenomicsBatchItems.push(metagenomicsBatchItem.data[0]); - } - return metagenomicsBatchItems; - } - - const usageType = molecularAnalysisRunItems.filter( - (runItem) => runItem.usageType !== "quality-control" - )?.[0]?.usageType; - - if (!usageType) { - setLoading(false); - return; - } - - setColumns( - useMolecularAnalysisRunColumns({ - type: usageType, - readOnly: true - }) - ); - - if (usageType === "seq-reaction") { - let seqReactions = await fetchSeqReactions(); - seqReactions = seqReactions.filter((item) => item !== undefined); - - // Chain it all together to create one object. - let sequencingRunItemsChain = attachSeqReaction(seqReactions); - sequencingRunItemsChain = await attachStorageUnitUsage( - sequencingRunItemsChain, - bulkGet - ); - - sequencingRunItemsChain = await attachPcrBatchItem( - sequencingRunItemsChain, - bulkGet - ); - sequencingRunItemsChain = await attachMaterialSampleSummary( - sequencingRunItemsChain, - bulkGet - ); - - // All finished loading. - setSequencingRunItems(sequencingRunItemsChain); - setLoading(false); - } else if (usageType === "generic-molecular-analysis-item") { - let genericMolecularAnalysisItems = - await fetchGenericMolecularAnalysisItems(); - genericMolecularAnalysisItems = genericMolecularAnalysisItems.filter( - (item) => item !== undefined - ); - - let sequencingRunItemsChain = attachGenericMolecularAnalysisItems( - genericMolecularAnalysisItems - ); - - sequencingRunItemsChain = await attachStorageUnitUsage( - sequencingRunItemsChain, - bulkGet - ); - - sequencingRunItemsChain = await attachMaterialSampleSummary( - sequencingRunItemsChain, - bulkGet - ); - - const qualityControlRunItems = molecularAnalysisRunItems.filter( - (runItem) => runItem.usageType === "quality-control" - ); - - // Get quality controls - if (qualityControlRunItems && qualityControlRunItems?.length > 0) { - const newQualityControls: QualityControl[] = []; - - // Go through each quality control run item and then we do a query for each quality control. - for (const item of qualityControlRunItems) { - const qualityControlQuery = await apiClient.get( - `seqdb-api/quality-control`, - { - filter: filterBy([], { - extraFilters: [ - { - selector: "molecularAnalysisRunItem.uuid", - comparison: "==", - arguments: item?.id - } - ] - })(""), - include: "molecularAnalysisRunItem" - } - ); - - const qualityControlFound = qualityControlQuery - ?.data?.[0] as QualityControl; - if (qualityControlFound) { - newQualityControls.push({ - ...qualityControlFound - }); - } - } - - setQualityControls(newQualityControls); - } - - // All finished loading. - setSequencingRunItems(sequencingRunItemsChain); - setLoading(false); - } else if (usageType === "metagenomics-batch-item") { - let metagenomicsBatchItems = await fetchMetagenomicsBatchItems(); - metagenomicsBatchItems = metagenomicsBatchItems.filter( - (item) => item !== undefined - ); - - // Chain it all together to create one object. - let sequencingRunItemsChain = attachMetagenomicsBatchItem( - metagenomicsBatchItems - ); - sequencingRunItemsChain = await attachPcrBatchItemMetagenomics( - sequencingRunItemsChain, - bulkGet - ); - sequencingRunItemsChain = await attachStorageUnitUsageMetagenomics( - sequencingRunItemsChain, - bulkGet - ); - sequencingRunItemsChain = - await attachMaterialSampleSummaryMetagenomics( - sequencingRunItemsChain, - bulkGet - ); - // All finished loading. - setSequencingRunItems(sequencingRunItemsChain); - setLoading(false); - } - } - } - ); - return { - loading: - molecularAnalysisRunItemQuery.loading || - loadingVocabularyItems || - loading, - sequencingRunItems, - columns, - qualityControls, - qualityControlTypes - }; -} - -interface UseMolecularAnalysisRunColumnsProps { - type: string; - setMolecularAnalysisRunItemNames?: Dispatch< - SetStateAction> - >; - readOnly?: boolean; - setReloadGenericMolecularAnalysisRun?: Dispatch>; -} - -export function useMolecularAnalysisRunColumns({ - type, - setMolecularAnalysisRunItemNames, - readOnly, - setReloadGenericMolecularAnalysisRun -}: UseMolecularAnalysisRunColumnsProps) { - const { compareByStringAndNumber } = useStringComparator(); - const { save } = useApiClient(); - const { groupNames } = useAccount(); - - // Table columns to display for the sequencing run. - const SEQ_REACTION_COLUMNS: ColumnDef[] = [ - { - id: "materialSampleName", - cell: ({ row: { original } }) => { - const materialSampleName = - original?.materialSampleSummary?.materialSampleName; - return ( - <> - - {materialSampleName || original.materialSampleId} - - {" ("} - {original?.seqReaction?.seqPrimer?.name} - {")"} - - ); - }, - header: () => , - accessorKey: "materialSampleSummary.materialSampleName", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "molecularAnalysisRunItem.name", - cell: ({ row: { original } }) => { - return readOnly ? ( - <>{original.molecularAnalysisRunItem?.name} - ) : ( - ) => { - setMolecularAnalysisRunItemNames?.( - handleMolecularAnalysisRunItemNames(original, event) - ); - }} - /> - ); - }, - header: () => , - accessorKey: "molecularAnalysisRunItem.name", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "wellCoordinates", - cell: ({ row }) => { - return ( - <> - {!row.original?.storageUnitUsage || - row.original?.storageUnitUsage?.wellRow === null || - row.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${row.original.storageUnitUsage?.wellRow}${row.original.storageUnitUsage?.wellColumn}`} - - ); - }, - header: () => , - accessorKey: "wellCoordinates", - sortingFn: (a: any, b: any): number => { - const aString = - !a.original?.storageUnitUsage || - a.original?.storageUnitUsage?.wellRow === null || - a.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${a.original.storageUnitUsage?.wellRow}${a.original.storageUnitUsage?.wellColumn}`; - const bString = - !b.original?.storageUnitUsage || - b.original?.storageUnitUsage?.wellRow === null || - b.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${b.original.storageUnitUsage?.wellRow}${b.original.storageUnitUsage?.wellColumn}`; - return compareByStringAndNumber(aString, bString); - } - }, - { - id: "tubeNumber", - cell: ({ row: { original } }) => - original?.storageUnitUsage?.cellNumber === undefined ? ( - <> - ) : ( - <>{original.storageUnitUsage?.cellNumber} - ), - header: () => , - accessorKey: "tubeNumber", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.storageUnitUsage?.cellNumber?.toString(), - b?.original?.storageUnitUsage?.cellNumber?.toString() - ) - } - ]; - - const GENERIC_MOLECULAR_ANALYSIS_COLUMNS: ColumnDef[] = [ - { - id: "materialSampleName", - cell: ({ row: { original } }) => { - const materialSampleName = - original?.materialSampleSummary?.materialSampleName; - return ( - <> - - {materialSampleName || original.materialSampleId} - - - ); - }, - header: () => , - accessorKey: "materialSampleSummary.materialSampleName", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "molecularAnalysisRunItem.name", - cell: ({ row: { original } }) => { - return readOnly ? ( - <>{original.molecularAnalysisRunItem?.name} - ) : ( - ) => { - setMolecularAnalysisRunItemNames?.( - handleMolecularAnalysisRunItemNames(original, event) - ); - }} - /> - ); - }, - header: () => , - accessorKey: "molecularAnalysisRunItem.name", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "wellCoordinates", - cell: ({ row }) => { - return ( - <> - {!row.original?.storageUnitUsage || - row.original?.storageUnitUsage?.wellRow === null || - row.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${row.original.storageUnitUsage?.wellRow}${row.original.storageUnitUsage?.wellColumn}`} - - ); - }, - header: () => , - accessorKey: "wellCoordinates", - sortingFn: (a: any, b: any): number => { - const aString = - !a.original?.storageUnitUsage || - a.original?.storageUnitUsage?.wellRow === null || - a.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${a.original.storageUnitUsage?.wellRow}${a.original.storageUnitUsage?.wellColumn}`; - const bString = - !b.original?.storageUnitUsage || - b.original?.storageUnitUsage?.wellRow === null || - b.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${b.original.storageUnitUsage?.wellRow}${b.original.storageUnitUsage?.wellColumn}`; - return compareByStringAndNumber(aString, bString); - } - }, - { - id: "tubeNumber", - cell: ({ row: { original } }) => - original?.storageUnitUsage?.cellNumber === undefined ? ( - <> - ) : ( - <>{original.storageUnitUsage?.cellNumber} - ), - header: () => , - accessorKey: "tubeNumber", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.storageUnitUsage?.cellNumber?.toString(), - b?.original?.storageUnitUsage?.cellNumber?.toString() - ) - } - ]; - - const GENERIC_MOLECULAR_ANALYSIS_RESULTS_COLUMNS: ColumnDef[] = - [ - { - id: "materialSampleName", - cell: ({ row: { original } }) => { - const materialSampleName = - original?.materialSampleSummary?.materialSampleName; - return ( - <> - - {materialSampleName || original.materialSampleId} - - - ); - }, - header: () => , - accessorKey: "materialSampleSummary.materialSampleName", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "molecularAnalysisRunItem.name", - cell: ({ row: { original } }) => { - return readOnly ? ( - <>{original.molecularAnalysisRunItem?.name} - ) : ( - ) => { - setMolecularAnalysisRunItemNames?.( - (molecularAnalysisRunItemNames) => { - const molecularAnalysisRunItemNamesMap = - molecularAnalysisRunItemNames; - if ( - original?.materialSampleSummary?.id && - event.target.value - ) { - molecularAnalysisRunItemNamesMap[ - original?.materialSampleSummary?.id - ] = event.target.value; - } - return molecularAnalysisRunItemNamesMap; - } - ); - }} - /> - ); - }, - header: () => , - accessorKey: "molecularAnalysisRunItem.name", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "resultAttachment", - cell: ({ row: { original } }) => { - const attachments = - original.molecularAnalysisRunItem?.result?.attachments ?? []; - const attachmentElements = attachments?.map((attachment, index) => - attachment ? ( - - - {attachment?.originalFilename} - - {index < attachments?.length - 1 && ", "} - - ) : null - ); - - return ( - <>{attachmentElements?.length > 0 ? attachmentElements : null} - ); - }, - header: () => , - accessorKey: "resultAttachment", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.storageUnitUsage?.cellNumber?.toString(), - b?.original?.storageUnitUsage?.cellNumber?.toString() - ) - }, - { - id: "action", - cell: ({ row: { original } }) => { - return ( -
- } - value={ - (original.molecularAnalysisRunItem?.result - ?.attachments as ResourceIdentifierObject[]) ?? [] - } - onChange={async (newMetadatas) => { - if (original.molecularAnalysisRunItem) { - const molecularAnalysisRunResultSaveArgs: SaveArgs[] = - [ - { - type: "molecular-analysis-result", - resource: { - type: "molecular-analysis-result", - group: groupNames?.[0], - relationships: { - attachments: { - data: newMetadatas as Metadata[] - } - } - } - } as any - ]; - - const savedMolecularAnalysisResult = - await save?.( - molecularAnalysisRunResultSaveArgs, - { - apiBaseUrl: "seqdb-api/molecular-analysis-result" - } - ); - const molecularAnalysisRunItemSaveArgs: SaveArgs[] = - [ - { - type: "molecular-analysis-run-item", - resource: { - ...original.molecularAnalysisRunItem, - relationships: { - result: { - data: { - id: savedMolecularAnalysisResult?.[0].id, - type: "molecular-analysis-result" - } - } - } - } - } as any - ]; - await save?.( - molecularAnalysisRunItemSaveArgs, - { - apiBaseUrl: "seqdb-api/molecular-analysis-run-item" - } - ); - setReloadGenericMolecularAnalysisRun?.(Date.now()); - } - }} - />, - - ]} - /> -
- ); - }, - header: () => , - accessorKey: "action", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.storageUnitUsage?.cellNumber?.toString(), - b?.original?.storageUnitUsage?.cellNumber?.toString() - ) - } - ]; - - const METAGENOMICS_BATCH_ITEM_COLUMNS: ColumnDef[] = [ - { - id: "materialSampleName", - cell: ({ row: { original } }) => { - const materialSampleName = - original?.materialSampleSummary?.materialSampleName; - return ( - <> - - {materialSampleName || original.materialSampleId} - - - ); - }, - header: () => , - accessorKey: "materialSampleSummary.materialSampleName", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "molecularAnalysisRunItem.name", - cell: ({ row: { original } }) => { - return readOnly ? ( - <>{original.molecularAnalysisRunItem?.name} - ) : ( - ) => { - setMolecularAnalysisRunItemNames?.( - handleMolecularAnalysisRunItemNames(original, event) - ); - }} - /> - ); - }, - header: () => , - accessorKey: "molecularAnalysisRunItem.name", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.materialSampleSummary?.materialSampleName, - b?.original?.materialSampleSummary?.materialSampleName - ), - enableSorting: true - }, - { - id: "wellCoordinates", - cell: ({ row }) => { - return ( - <> - {!row.original?.storageUnitUsage || - row.original?.storageUnitUsage?.wellRow === null || - row.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${row.original.storageUnitUsage?.wellRow}${row.original.storageUnitUsage?.wellColumn}`} - - ); - }, - header: () => , - accessorKey: "wellCoordinates", - sortingFn: (a: any, b: any): number => { - const aString = - !a.original?.storageUnitUsage || - a.original?.storageUnitUsage?.wellRow === null || - a.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${a.original.storageUnitUsage?.wellRow}${a.original.storageUnitUsage?.wellColumn}`; - const bString = - !b.original?.storageUnitUsage || - b.original?.storageUnitUsage?.wellRow === null || - b.original?.storageUnitUsage?.wellColumn === null - ? "" - : `${b.original.storageUnitUsage?.wellRow}${b.original.storageUnitUsage?.wellColumn}`; - return compareByStringAndNumber(aString, bString); - } - }, - { - id: "tubeNumber", - cell: ({ row: { original } }) => - original?.storageUnitUsage?.cellNumber === undefined ? ( - <> - ) : ( - <>{original.storageUnitUsage?.cellNumber} - ), - header: () => , - accessorKey: "tubeNumber", - sortingFn: (a: any, b: any): number => - compareByStringAndNumber( - a?.original?.storageUnitUsage?.cellNumber?.toString(), - b?.original?.storageUnitUsage?.cellNumber?.toString() - ) - } - ]; - const MOLECULAR_ANALYSIS_RUN_COLUMNS_MAP = { - "seq-reaction": SEQ_REACTION_COLUMNS, - "generic-molecular-analysis-item": GENERIC_MOLECULAR_ANALYSIS_COLUMNS, - "metagenomics-batch-item": METAGENOMICS_BATCH_ITEM_COLUMNS, - "generic-molecular-analysis-results": - GENERIC_MOLECULAR_ANALYSIS_RESULTS_COLUMNS - }; - return MOLECULAR_ANALYSIS_RUN_COLUMNS_MAP[type]; - - function handleMolecularAnalysisRunItemNames( - original: SequencingRunItem, - event: ChangeEvent - ): SetStateAction> { - return (molecularAnalysisRunItemNames) => { - const molecularAnalysisRunItemNamesMap = molecularAnalysisRunItemNames; - if (original?.materialSampleSummary?.id) { - molecularAnalysisRunItemNamesMap[original?.materialSampleSummary?.id] = - event.target.value; - } - return molecularAnalysisRunItemNamesMap; - }; - } -} diff --git a/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunColumns.tsx b/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunColumns.tsx new file mode 100644 index 000000000..19eb69d65 --- /dev/null +++ b/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunColumns.tsx @@ -0,0 +1,610 @@ +import { ChangeEvent, Dispatch, SetStateAction } from "react"; +import { + DeleteArgs, + FieldHeader, + SaveArgs, + SettingsButton, + useAccount, + useApiClient, + useStringComparator +} from "common-ui"; +import { DinaMessage } from "../../intl/dina-ui-intl"; +import { ColumnDef } from "@tanstack/react-table"; +import Link from "next/link"; +import { MolecularAnalysisRunItem } from "packages/dina-ui/types/seqdb-api/resources/molecular-analysis/MolecularAnalysisRunItem"; +import { ResourceIdentifierObject } from "jsonapi-typescript"; +import { AddAttachmentsButton } from "../object-store"; +import { MolecularAnalysisResult } from "packages/dina-ui/types/seqdb-api/resources/molecular-analysis/MolecularAnalysisResult"; +import { Metadata } from "packages/dina-ui/types/objectstore-api"; +import React from "react"; +import { SequencingRunItem } from "./useMolecularAnalysisRun"; + +interface UseMolecularAnalysisRunColumnsProps { + type: string; + setMolecularAnalysisRunItemNames?: Dispatch< + SetStateAction> + >; + readOnly?: boolean; + setReloadGenericMolecularAnalysisRun?: Dispatch>; +} + +export function useMolecularAnalysisRunColumns({ + type, + setMolecularAnalysisRunItemNames, + readOnly, + setReloadGenericMolecularAnalysisRun +}: UseMolecularAnalysisRunColumnsProps) { + const { compareByStringAndNumber } = useStringComparator(); + const { save } = useApiClient(); + const { groupNames } = useAccount(); + + // Table columns to display for the sequencing run. + const SEQ_REACTION_COLUMNS: ColumnDef[] = [ + { + id: "materialSampleName", + cell: ({ row: { original } }) => { + const materialSampleName = + original?.materialSampleSummary?.materialSampleName; + return ( + <> + + {materialSampleName || original.materialSampleId} + + {" ("} + {original?.seqReaction?.seqPrimer?.name} + {")"} + + ); + }, + header: () => , + accessorKey: "materialSampleSummary.materialSampleName", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "molecularAnalysisRunItem.name", + cell: ({ row: { original } }) => { + return readOnly ? ( + <>{original.molecularAnalysisRunItem?.name} + ) : ( + ) => { + setMolecularAnalysisRunItemNames?.( + handleMolecularAnalysisRunItemNames(original, event) + ); + }} + /> + ); + }, + header: () => , + accessorKey: "molecularAnalysisRunItem.name", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "wellCoordinates", + cell: ({ row }) => { + return ( + <> + {!row.original?.storageUnitUsage || + row.original?.storageUnitUsage?.wellRow === null || + row.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${row.original.storageUnitUsage?.wellRow}${row.original.storageUnitUsage?.wellColumn}`} + + ); + }, + header: () => , + accessorKey: "wellCoordinates", + sortingFn: (a: any, b: any): number => { + const aString = + !a.original?.storageUnitUsage || + a.original?.storageUnitUsage?.wellRow === null || + a.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${a.original.storageUnitUsage?.wellRow}${a.original.storageUnitUsage?.wellColumn}`; + const bString = + !b.original?.storageUnitUsage || + b.original?.storageUnitUsage?.wellRow === null || + b.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${b.original.storageUnitUsage?.wellRow}${b.original.storageUnitUsage?.wellColumn}`; + return compareByStringAndNumber(aString, bString); + } + }, + { + id: "tubeNumber", + cell: ({ row: { original } }) => + original?.storageUnitUsage?.cellNumber === undefined ? ( + <> + ) : ( + <>{original.storageUnitUsage?.cellNumber} + ), + header: () => , + accessorKey: "tubeNumber", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.storageUnitUsage?.cellNumber?.toString(), + b?.original?.storageUnitUsage?.cellNumber?.toString() + ) + } + ]; + + const GENERIC_MOLECULAR_ANALYSIS_COLUMNS: ColumnDef[] = [ + { + id: "materialSampleName", + cell: ({ row: { original } }) => { + const materialSampleName = + original?.materialSampleSummary?.materialSampleName; + return ( + <> + + {materialSampleName || original.materialSampleId} + + + ); + }, + header: () => , + accessorKey: "materialSampleSummary.materialSampleName", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "molecularAnalysisRunItem.name", + cell: ({ row: { original } }) => { + return readOnly ? ( + <>{original.molecularAnalysisRunItem?.name} + ) : ( + ) => { + setMolecularAnalysisRunItemNames?.( + handleMolecularAnalysisRunItemNames(original, event) + ); + }} + /> + ); + }, + header: () => , + accessorKey: "molecularAnalysisRunItem.name", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "wellCoordinates", + cell: ({ row }) => { + return ( + <> + {!row.original?.storageUnitUsage || + row.original?.storageUnitUsage?.wellRow === null || + row.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${row.original.storageUnitUsage?.wellRow}${row.original.storageUnitUsage?.wellColumn}`} + + ); + }, + header: () => , + accessorKey: "wellCoordinates", + sortingFn: (a: any, b: any): number => { + const aString = + !a.original?.storageUnitUsage || + a.original?.storageUnitUsage?.wellRow === null || + a.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${a.original.storageUnitUsage?.wellRow}${a.original.storageUnitUsage?.wellColumn}`; + const bString = + !b.original?.storageUnitUsage || + b.original?.storageUnitUsage?.wellRow === null || + b.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${b.original.storageUnitUsage?.wellRow}${b.original.storageUnitUsage?.wellColumn}`; + return compareByStringAndNumber(aString, bString); + } + }, + { + id: "tubeNumber", + cell: ({ row: { original } }) => + original?.storageUnitUsage?.cellNumber === undefined ? ( + <> + ) : ( + <>{original.storageUnitUsage?.cellNumber} + ), + header: () => , + accessorKey: "tubeNumber", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.storageUnitUsage?.cellNumber?.toString(), + b?.original?.storageUnitUsage?.cellNumber?.toString() + ) + } + ]; + + const GENERIC_MOLECULAR_ANALYSIS_RESULTS_COLUMNS: ColumnDef[] = + [ + { + id: "materialSampleName", + cell: ({ row: { original } }) => { + const materialSampleName = + original?.materialSampleSummary?.materialSampleName; + return ( + <> + + {materialSampleName || original.materialSampleId} + + + ); + }, + header: () => , + accessorKey: "materialSampleSummary.materialSampleName", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "molecularAnalysisRunItem.name", + cell: ({ row: { original } }) => { + return readOnly ? ( + <>{original.molecularAnalysisRunItem?.name} + ) : ( + ) => { + setMolecularAnalysisRunItemNames?.( + (molecularAnalysisRunItemNames) => { + const molecularAnalysisRunItemNamesMap = + molecularAnalysisRunItemNames; + if ( + original?.materialSampleSummary?.id && + event.target.value + ) { + molecularAnalysisRunItemNamesMap[ + original?.materialSampleSummary?.id + ] = event.target.value; + } + return molecularAnalysisRunItemNamesMap; + } + ); + }} + /> + ); + }, + header: () => , + accessorKey: "molecularAnalysisRunItem.name", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "resultAttachment", + cell: ({ row: { original } }) => { + const attachments = + original.molecularAnalysisRunItem?.result?.attachments ?? []; + const attachmentElements = attachments?.map((attachment, index) => + attachment ? ( + + + {attachment?.originalFilename} + + {index < attachments?.length - 1 && ", "} + + ) : null + ); + + return ( + <>{attachmentElements?.length > 0 ? attachmentElements : null} + ); + }, + header: () => , + accessorKey: "resultAttachment", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.storageUnitUsage?.cellNumber?.toString(), + b?.original?.storageUnitUsage?.cellNumber?.toString() + ) + }, + { + id: "action", + cell: ({ row: { original } }) => { + return ( +
+ } + value={ + (original.molecularAnalysisRunItem?.result + ?.attachments as ResourceIdentifierObject[]) ?? [] + } + onChange={async (newMetadatas) => { + if (original.molecularAnalysisRunItem) { + const molecularAnalysisRunResultSaveArgs: SaveArgs[] = + [ + { + type: "molecular-analysis-result", + resource: { + type: "molecular-analysis-result", + group: groupNames?.[0], + relationships: { + attachments: { + data: newMetadatas as Metadata[] + } + } + } + } as any + ]; + + const savedMolecularAnalysisResult = + await save?.( + molecularAnalysisRunResultSaveArgs, + { + apiBaseUrl: "seqdb-api/molecular-analysis-result" + } + ); + const molecularAnalysisRunItemSaveArgs: SaveArgs[] = + [ + { + type: "molecular-analysis-run-item", + resource: { + ...original.molecularAnalysisRunItem, + relationships: { + result: { + data: { + id: savedMolecularAnalysisResult?.[0].id, + type: "molecular-analysis-result" + } + } + } + } + } as any + ]; + await save?.( + molecularAnalysisRunItemSaveArgs, + { + apiBaseUrl: "seqdb-api/molecular-analysis-run-item" + } + ); + setReloadGenericMolecularAnalysisRun?.(Date.now()); + } + }} + />, + + ]} + /> +
+ ); + }, + header: () => , + accessorKey: "action", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.storageUnitUsage?.cellNumber?.toString(), + b?.original?.storageUnitUsage?.cellNumber?.toString() + ) + } + ]; + + const METAGENOMICS_BATCH_ITEM_COLUMNS: ColumnDef[] = [ + { + id: "materialSampleName", + cell: ({ row: { original } }) => { + const materialSampleName = + original?.materialSampleSummary?.materialSampleName; + return ( + <> + + {materialSampleName || original.materialSampleId} + + + ); + }, + header: () => , + accessorKey: "materialSampleSummary.materialSampleName", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "molecularAnalysisRunItem.name", + cell: ({ row: { original } }) => { + return readOnly ? ( + <>{original.molecularAnalysisRunItem?.name} + ) : ( + ) => { + setMolecularAnalysisRunItemNames?.( + handleMolecularAnalysisRunItemNames(original, event) + ); + }} + /> + ); + }, + header: () => , + accessorKey: "molecularAnalysisRunItem.name", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.materialSampleSummary?.materialSampleName, + b?.original?.materialSampleSummary?.materialSampleName + ), + enableSorting: true + }, + { + id: "wellCoordinates", + cell: ({ row }) => { + return ( + <> + {!row.original?.storageUnitUsage || + row.original?.storageUnitUsage?.wellRow === null || + row.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${row.original.storageUnitUsage?.wellRow}${row.original.storageUnitUsage?.wellColumn}`} + + ); + }, + header: () => , + accessorKey: "wellCoordinates", + sortingFn: (a: any, b: any): number => { + const aString = + !a.original?.storageUnitUsage || + a.original?.storageUnitUsage?.wellRow === null || + a.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${a.original.storageUnitUsage?.wellRow}${a.original.storageUnitUsage?.wellColumn}`; + const bString = + !b.original?.storageUnitUsage || + b.original?.storageUnitUsage?.wellRow === null || + b.original?.storageUnitUsage?.wellColumn === null + ? "" + : `${b.original.storageUnitUsage?.wellRow}${b.original.storageUnitUsage?.wellColumn}`; + return compareByStringAndNumber(aString, bString); + } + }, + { + id: "tubeNumber", + cell: ({ row: { original } }) => + original?.storageUnitUsage?.cellNumber === undefined ? ( + <> + ) : ( + <>{original.storageUnitUsage?.cellNumber} + ), + header: () => , + accessorKey: "tubeNumber", + sortingFn: (a: any, b: any): number => + compareByStringAndNumber( + a?.original?.storageUnitUsage?.cellNumber?.toString(), + b?.original?.storageUnitUsage?.cellNumber?.toString() + ) + } + ]; + const MOLECULAR_ANALYSIS_RUN_COLUMNS_MAP = { + "seq-reaction": SEQ_REACTION_COLUMNS, + "generic-molecular-analysis-item": GENERIC_MOLECULAR_ANALYSIS_COLUMNS, + "metagenomics-batch-item": METAGENOMICS_BATCH_ITEM_COLUMNS, + "generic-molecular-analysis-results": + GENERIC_MOLECULAR_ANALYSIS_RESULTS_COLUMNS + }; + return MOLECULAR_ANALYSIS_RUN_COLUMNS_MAP[type]; + + function handleMolecularAnalysisRunItemNames( + original: SequencingRunItem, + event: ChangeEvent + ): SetStateAction> { + return (molecularAnalysisRunItemNames) => { + const molecularAnalysisRunItemNamesMap = molecularAnalysisRunItemNames; + if (original?.materialSampleSummary?.id) { + molecularAnalysisRunItemNamesMap[original?.materialSampleSummary?.id] = + event.target.value; + } + return molecularAnalysisRunItemNamesMap; + }; + } +} diff --git a/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunView.tsx b/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunView.tsx new file mode 100644 index 000000000..92771a02a --- /dev/null +++ b/packages/dina-ui/components/molecular-analysis/useMolecularAnalysisRunView.tsx @@ -0,0 +1,255 @@ +import { SeqReaction } from "../../types/seqdb-api"; +import { useState } from "react"; +import { filterBy, useApiClient, useQuery } from "common-ui"; +import { PersistedResource } from "kitsu"; +import { attachGenericMolecularAnalysisItems } from "../seqdb/molecular-analysis-workflow/useGenericMolecularAnalysisRun"; +import { GenericMolecularAnalysisItem } from "packages/dina-ui/types/seqdb-api/resources/GenericMolecularAnalysisItem"; +import { MolecularAnalysisRunItem } from "packages/dina-ui/types/seqdb-api/resources/molecular-analysis/MolecularAnalysisRunItem"; +import { MetagenomicsBatchItem } from "packages/dina-ui/types/seqdb-api/resources/metagenomics/MetagenomicsBatchItem"; +import { + attachMaterialSampleSummaryMetagenomics, + attachMetagenomicsBatchItem, + attachPcrBatchItemMetagenomics, + attachStorageUnitUsageMetagenomics +} from "./useMetagenomicsWorkflowMolecularAnalysisRun"; +import { QualityControl } from "packages/dina-ui/types/seqdb-api/resources/QualityControl"; +import useVocabularyOptions from "../collection/useVocabularyOptions"; +import { useMolecularAnalysisRunColumns } from "./useMolecularAnalysisRunColumns"; +import { + attachMaterialSampleSummary, + attachPcrBatchItem, + attachSeqReaction, + attachStorageUnitUsage, + SequencingRunItem +} from "./useMolecularAnalysisRun"; + +export interface UseMolecularAnalysisRunViewProps { + molecularAnalysisRunId: string; +} + +/** + * Used for the Molecular Analysis Run View page. The Molecular Analysis Run + * is loaded from the ViewPageLayout component. + */ +export function useMolecularAnalysisRunView({ + molecularAnalysisRunId +}: UseMolecularAnalysisRunViewProps) { + const { apiClient, bulkGet } = useApiClient(); + const [columns, setColumns] = useState([]); + // Run Items + const [sequencingRunItems, setSequencingRunItems] = + useState(); + const [loading, setLoading] = useState(true); + + // Quality control items + const [qualityControls, setQualityControls] = useState([]); + const { loading: loadingVocabularyItems, vocabOptions: qualityControlTypes } = + useVocabularyOptions({ + path: "seqdb-api/vocabulary/qualityControlType" + }); + const molecularAnalysisRunItemQuery = useQuery( + { + path: `seqdb-api/molecular-analysis-run-item`, + filter: filterBy([], { + extraFilters: [ + { + selector: "run.uuid", + comparison: "==", + arguments: molecularAnalysisRunId + } + ] + })("") + }, + { + onSuccess: async ({ data: molecularAnalysisRunItems }) => { + async function fetchSeqReactions() { + const fetchPaths = molecularAnalysisRunItems.map( + (molecularAnalysisRunItem) => + `seqdb-api/seq-reaction?include=storageUnitUsage,pcrBatchItem,seqPrimer&filter[rsql]=molecularAnalysisRunItem.uuid==${molecularAnalysisRunItem.id}` + ); + const seqReactions: PersistedResource[] = []; + for (const path of fetchPaths) { + const seqReaction = await apiClient.get(path, {}); + seqReactions.push(seqReaction.data[0]); + } + return seqReactions; + } + + async function fetchGenericMolecularAnalysisItems() { + const fetchPaths = molecularAnalysisRunItems + .filter((runItem) => runItem.usageType !== "quality-control") + .map( + (molecularAnalysisRunItem) => + `seqdb-api/generic-molecular-analysis-item?include=storageUnitUsage,materialSample,molecularAnalysisRunItem&filter[rsql]=molecularAnalysisRunItem.uuid==${molecularAnalysisRunItem.id}` + ); + const genericMolecularAnalysisItems: PersistedResource[] = + []; + for (const path of fetchPaths) { + const genericMolecularAnalysisItem = await apiClient.get< + GenericMolecularAnalysisItem[] + >(path, {}); + genericMolecularAnalysisItems.push( + genericMolecularAnalysisItem.data[0] + ); + } + return genericMolecularAnalysisItems; + } + + async function fetchMetagenomicsBatchItems() { + const fetchPaths = molecularAnalysisRunItems.map( + (molecularAnalysisRunItem) => + `seqdb-api/metagenomics-batch-item?include=pcrBatchItem&filter[rsql]=molecularAnalysisRunItem.uuid==${molecularAnalysisRunItem.id}` + ); + const metagenomicsBatchItems: PersistedResource[] = + []; + for (const path of fetchPaths) { + const metagenomicsBatchItem = await apiClient.get< + MetagenomicsBatchItem[] + >(path, {}); + metagenomicsBatchItems.push(metagenomicsBatchItem.data[0]); + } + return metagenomicsBatchItems; + } + + const usageType = molecularAnalysisRunItems.filter( + (runItem) => runItem.usageType !== "quality-control" + )?.[0]?.usageType; + + if (!usageType) { + setLoading(false); + return; + } + + setColumns( + useMolecularAnalysisRunColumns({ + type: usageType, + readOnly: true + }) + ); + + if (usageType === "seq-reaction") { + let seqReactions = await fetchSeqReactions(); + seqReactions = seqReactions.filter((item) => item !== undefined); + + // Chain it all together to create one object. + let sequencingRunItemsChain = attachSeqReaction(seqReactions); + sequencingRunItemsChain = await attachStorageUnitUsage( + sequencingRunItemsChain, + bulkGet + ); + + sequencingRunItemsChain = await attachPcrBatchItem( + sequencingRunItemsChain, + bulkGet + ); + sequencingRunItemsChain = await attachMaterialSampleSummary( + sequencingRunItemsChain, + bulkGet + ); + + // All finished loading. + setSequencingRunItems(sequencingRunItemsChain); + setLoading(false); + } else if (usageType === "generic-molecular-analysis-item") { + let genericMolecularAnalysisItems = + await fetchGenericMolecularAnalysisItems(); + genericMolecularAnalysisItems = genericMolecularAnalysisItems.filter( + (item) => item !== undefined + ); + + let sequencingRunItemsChain = attachGenericMolecularAnalysisItems( + genericMolecularAnalysisItems + ); + + sequencingRunItemsChain = await attachStorageUnitUsage( + sequencingRunItemsChain, + bulkGet + ); + + sequencingRunItemsChain = await attachMaterialSampleSummary( + sequencingRunItemsChain, + bulkGet + ); + + const qualityControlRunItems = molecularAnalysisRunItems.filter( + (runItem) => runItem.usageType === "quality-control" + ); + + // Get quality controls + if (qualityControlRunItems && qualityControlRunItems?.length > 0) { + const newQualityControls: QualityControl[] = []; + + // Go through each quality control run item and then we do a query for each quality control. + for (const item of qualityControlRunItems) { + const qualityControlQuery = await apiClient.get( + `seqdb-api/quality-control`, + { + filter: filterBy([], { + extraFilters: [ + { + selector: "molecularAnalysisRunItem.uuid", + comparison: "==", + arguments: item?.id + } + ] + })(""), + include: "molecularAnalysisRunItem" + } + ); + + const qualityControlFound = qualityControlQuery + ?.data?.[0] as QualityControl; + if (qualityControlFound) { + newQualityControls.push({ + ...qualityControlFound + }); + } + } + + setQualityControls(newQualityControls); + } + + // All finished loading. + setSequencingRunItems(sequencingRunItemsChain); + setLoading(false); + } else if (usageType === "metagenomics-batch-item") { + let metagenomicsBatchItems = await fetchMetagenomicsBatchItems(); + metagenomicsBatchItems = metagenomicsBatchItems.filter( + (item) => item !== undefined + ); + + // Chain it all together to create one object. + let sequencingRunItemsChain = attachMetagenomicsBatchItem( + metagenomicsBatchItems + ); + sequencingRunItemsChain = await attachPcrBatchItemMetagenomics( + sequencingRunItemsChain, + bulkGet + ); + sequencingRunItemsChain = await attachStorageUnitUsageMetagenomics( + sequencingRunItemsChain, + bulkGet + ); + sequencingRunItemsChain = + await attachMaterialSampleSummaryMetagenomics( + sequencingRunItemsChain, + bulkGet + ); + // All finished loading. + setSequencingRunItems(sequencingRunItemsChain); + setLoading(false); + } + } + } + ); + return { + loading: + molecularAnalysisRunItemQuery.loading || + loadingVocabularyItems || + loading, + sequencingRunItems, + columns, + qualityControls, + qualityControlTypes + }; +}