diff --git a/frontend/src/components/individuals/IndividualAssociatedSamples.tsx b/frontend/src/components/individuals/IndividualAssociatedSamples.tsx
index 0b6ee619e7..bbb3d7ad4c 100644
--- a/frontend/src/components/individuals/IndividualAssociatedSamples.tsx
+++ b/frontend/src/components/individuals/IndividualAssociatedSamples.tsx
@@ -1,94 +1,97 @@
import React, { useMemo, useCallback } from "react"
-import { SAMPLE_COLUMN_DEFINITIONS as SAMPLE_COLUMNS, SAMPLE_COLUMN_FILTERS, SampleColumnID } from '../samples/SampleTableColumns';
-import { clearFilters, setFilter, setSortBy } from '../../modules/individualDetails/actions'
-import { FilterDescription, FilterValue, SortBy } from "../../models/paged_items";
-import { useAppDispatch } from "../../hooks";
-import { IndividualDetails } from "../../modules/individualDetails/models";
-import { SampleAndLibrary } from "../WorkflowSamplesTable/ColumnSets";
-import WorkflowSamplesTable from '../WorkflowSamplesTable/WorkflowSamplesTable'
+import {
+ SAMPLE_COLUMN_DEFINITIONS as SAMPLE_COLUMNS,
+ SAMPLE_COLUMN_FILTERS,
+ SampleColumnID,
+} from "../samples/SampleTableColumns"
+import { clearFilters, setFilter, setSortBy } from "../../modules/individualDetails/actions"
+import { FilterDescription, FilterValue, SortBy } from "../../models/paged_items"
+import { useAppDispatch } from "../../hooks"
+import { IndividualDetails } from "../../modules/individualDetails/models"
+import { SampleAndLibraryAndIdentity } from "../WorkflowSamplesTable/ColumnSets"
+import WorkflowSamplesTable from "../WorkflowSamplesTable/WorkflowSamplesTable"
interface IndividualAssociatedSamplesProps {
- samples: SampleAndLibrary[],
- individual: IndividualDetails
+ samples: SampleAndLibraryAndIdentity[]
+ individual: IndividualDetails
}
const IndividualAssociatedSamples = ({ samples, individual }: IndividualAssociatedSamplesProps) => {
+ const dispatch = useAppDispatch()
- const dispatch = useAppDispatch();
+ const handleSetFilter = useCallback(
+ (filterKey: string, value: FilterValue, description: FilterDescription) => {
+ if (typeof description === "undefined") {
+ return
+ }
+ if (individual.individual) dispatch(setFilter(individual.individual.id, description, value))
+ },
+ [dispatch],
+ )
+ const handleSetSortBy = useCallback(
+ (sortBy: SortBy) => {
+ if (individual.individual) dispatch(setSortBy(individual.individual.id, sortBy))
+ },
+ [dispatch],
+ )
+ const columnsForSelection = useMemo(() => {
+ const columns = [
+ SAMPLE_COLUMNS.ID,
+ SAMPLE_COLUMNS.KIND,
+ SAMPLE_COLUMNS.NAME,
+ SAMPLE_COLUMNS.PROJECT,
+ SAMPLE_COLUMNS.CONTAINER_BARCODE,
+ SAMPLE_COLUMNS.COORDINATES,
+ SAMPLE_COLUMNS.VOLUME,
+ SAMPLE_COLUMNS.CONCENTRATION,
+ SAMPLE_COLUMNS.QC_FLAG,
+ SAMPLE_COLUMNS.CREATION_DATE,
+ SAMPLE_COLUMNS.DEPLETED,
+ ]
+ return columns
+ }, [samples])
- const handleSetFilter = useCallback(
- (filterKey: string, value: FilterValue, description: FilterDescription) => {
- if (typeof description === 'undefined') {
- return
- }
- if (individual.individual)
- dispatch(setFilter(individual.individual.id, description, value))
- }, [dispatch]
- )
- const handleSetSortBy = useCallback(
- (sortBy: SortBy) => {
- if (individual.individual)
- dispatch(setSortBy(individual.individual.id, sortBy))
- },
- [dispatch]
- )
- const columnsForSelection = useMemo(() => {
- const columns = [
- SAMPLE_COLUMNS.ID,
- SAMPLE_COLUMNS.KIND,
- SAMPLE_COLUMNS.NAME,
- SAMPLE_COLUMNS.PROJECT,
- SAMPLE_COLUMNS.CONTAINER_BARCODE,
- SAMPLE_COLUMNS.COORDINATES,
- SAMPLE_COLUMNS.VOLUME,
- SAMPLE_COLUMNS.CONCENTRATION,
- SAMPLE_COLUMNS.QC_FLAG,
- SAMPLE_COLUMNS.CREATION_DATE,
- SAMPLE_COLUMNS.DEPLETED
- ]
- return columns
- }, [samples])
-
- const filterKeys = useMemo(() => {
- return {
- [SampleColumnID.ID]: 'id',
- [SampleColumnID.KIND]: 'derived_samples__sample_kind__name',
- [SampleColumnID.NAME]: 'name',
- [SampleColumnID.INDIVIDUAL]: 'derived_samples__biosample__individual__name',
- [SampleColumnID.CONTAINER_NAME]: 'container__name',
- [SampleColumnID.CONTAINER_BARCODE]: 'container__barcode',
- [SampleColumnID.COORDINATES]: 'coordinate__name',
- [SampleColumnID.VOLUME]: 'volume',
- [SampleColumnID.CONCENTRATION]: 'concentration',
- [SampleColumnID.CREATION_DATE]: 'creation_date',
- [SampleColumnID.DEPLETED]: 'depleted',
- [SampleColumnID.QC_FLAG]: 'qc_flag',
- [SampleColumnID.PROJECT]: 'derived_by_samples__project__name',
- }
- }, [])
+ const filterKeys = useMemo(() => {
+ return {
+ [SampleColumnID.ID]: "id",
+ [SampleColumnID.KIND]: "derived_samples__sample_kind__name",
+ [SampleColumnID.NAME]: "name",
+ [SampleColumnID.INDIVIDUAL]: "derived_samples__biosample__individual__name",
+ [SampleColumnID.CONTAINER_NAME]: "container__name",
+ [SampleColumnID.CONTAINER_BARCODE]: "container__barcode",
+ [SampleColumnID.COORDINATES]: "coordinate__name",
+ [SampleColumnID.VOLUME]: "volume",
+ [SampleColumnID.CONCENTRATION]: "concentration",
+ [SampleColumnID.CREATION_DATE]: "creation_date",
+ [SampleColumnID.DEPLETED]: "depleted",
+ [SampleColumnID.QC_FLAG]: "qc_flag",
+ [SampleColumnID.PROJECT]: "derived_by_samples__project__name",
+ }
+ }, [])
- const filterDefinitions = useMemo(() => {
- return { ...SAMPLE_COLUMN_FILTERS }
- }, [])
+ const filterDefinitions = useMemo(() => {
+ return { ...SAMPLE_COLUMN_FILTERS }
+ }, [])
- const localClearFilters = () => {
- if (clearFilters && individual.individual)
- dispatch(clearFilters(individual.individual.id))
- }
+ const localClearFilters = () => {
+ if (clearFilters && individual.individual) dispatch(clearFilters(individual.individual.id))
+ }
- return <>
-
+ return (
+ <>
+
>
+ )
}
-export default IndividualAssociatedSamples
\ No newline at end of file
+export default IndividualAssociatedSamples
diff --git a/frontend/src/components/individuals/IndividualsDetailContent.tsx b/frontend/src/components/individuals/IndividualsDetailContent.tsx
index 760eb3f786..7783198e78 100644
--- a/frontend/src/components/individuals/IndividualsDetailContent.tsx
+++ b/frontend/src/components/individuals/IndividualsDetailContent.tsx
@@ -1,78 +1,78 @@
-import React, { useEffect, useState } from "react";
-import { useParams } from "react-router-dom";
-import { Tabs } from 'antd'
-import useHashURL from '../../hooks/useHashURL'
-import AppPageHeader from "../AppPageHeader";
-import PageContent from "../PageContent";
-import EditButton from "../EditButton";
-import IndividualOverview from "./IndividualOverview";
-import { useAppDispatch, useAppSelector } from "../../hooks";
-import { selectIndividualsDetailsById } from "../../selectors";
-import IndividualAssociatedSamples from "./IndividualAssociatedSamples";
-import { flushIndividualDetails, listTable } from "../../modules/individualDetails/actions";
-import { IndividualDetails, IndividualDetailsById } from "../../modules/individualDetails/models";
-import { Sample } from "../../models/frontend_models";
-import { SampleAndLibrary } from "../WorkflowSamplesTable/ColumnSets";
+import React, { useEffect, useState } from "react"
+import { useParams } from "react-router-dom"
+import { Tabs } from "antd"
+import useHashURL from "../../hooks/useHashURL"
+import AppPageHeader from "../AppPageHeader"
+import PageContent from "../PageContent"
+import EditButton from "../EditButton"
+import IndividualOverview from "./IndividualOverview"
+import { useAppDispatch, useAppSelector } from "../../hooks"
+import { selectIndividualsDetailsById } from "../../selectors"
+import IndividualAssociatedSamples from "./IndividualAssociatedSamples"
+import { flushIndividualDetails, listTable } from "../../modules/individualDetails/actions"
+import { IndividualDetails, IndividualDetailsById } from "../../modules/individualDetails/models"
+import { Sample } from "../../models/frontend_models"
+import { SampleAndLibraryAndIdentity } from "../WorkflowSamplesTable/ColumnSets"
const IndividualsDetailContent = () => {
- const { id } = useParams();
- const dispatch = useAppDispatch()
- const individualDetailsById: IndividualDetailsById = useAppSelector(selectIndividualsDetailsById)
+ const { id } = useParams()
+ const dispatch = useAppDispatch()
+ const individualDetailsById: IndividualDetailsById = useAppSelector(selectIndividualsDetailsById)
- const [activeKey, setActiveKey] = useHashURL('overview')
- const [individual, setIndividual] = useState()
+ const [activeKey, setActiveKey] = useHashURL("overview")
+ const [individual, setIndividual] = useState()
- useEffect(() => {
- dispatch(listTable(Number(id)));
- }, [id, dispatch])
+ useEffect(() => {
+ dispatch(listTable(Number(id)))
+ }, [id, dispatch])
- useEffect(() => {
- // Flush the labwork state when the user navigates away from the
- // the labwork section.
- return () => {
- dispatch(flushIndividualDetails(Number(id)))
- }
- }, [dispatch, id])
- useEffect(() => {
- if (individualDetailsById[Number(id)]) {
- const individualInstance: IndividualDetails = {
- ...individualDetailsById[Number(id)]
- }
- if (individualInstance) {
- setIndividual(individualInstance)
- }
- }
- }, [individualDetailsById, id])
+ useEffect(() => {
+ // Flush the labwork state when the user navigates away from the
+ // the labwork section.
+ return () => {
+ dispatch(flushIndividualDetails(Number(id)))
+ }
+ }, [dispatch, id])
+ useEffect(() => {
+ if (individualDetailsById[Number(id)]) {
+ const individualInstance: IndividualDetails = {
+ ...individualDetailsById[Number(id)],
+ }
+ if (individualInstance) {
+ setIndividual(individualInstance)
+ }
+ }
+ }, [individualDetailsById, id])
- const samples = individual?.samplesByIndividual.items.reduce((acc, sampleID) => {
- const sample = individual?.samplesByIndividual.itemsByID[sampleID]
- if (sample) {
- acc.push({ sample: sample as Sample })
- }
- return acc
- }, [] as SampleAndLibrary[])
+ const samples = individual?.samplesByIndividual.items.reduce((acc, sampleID) => {
+ const sample = individual?.samplesByIndividual.itemsByID[sampleID]
+ if (sample) {
+ acc.push({ sample: sample as Sample })
+ }
+ return acc
+ }, [] as SampleAndLibraryAndIdentity[])
- const title =
- `Individual ${[id, (individual && individual.individual) ? individual.individual.name : undefined].filter(Boolean).join(' - ')}`;
+ const title = `Individual ${[id, individual && individual.individual ? individual.individual.name : undefined].filter(Boolean).join(" - ")}`
- return <>
- } />
-
-
-
-
-
-
- {
- individual && individual.individual.id &&
- < IndividualAssociatedSamples samples={samples ?? []} individual={individual} />
- }
-
-
-
- >;
+ return (
+ <>
+ } />
+
+
+
+
+
+
+ {individual && individual.individual.id && (
+
+ )}
+
+
+
+ >
+ )
+}
-
-};
-
-export default IndividualsDetailContent;
+export default IndividualsDetailContent
diff --git a/frontend/src/components/labwork/step/LabworkSelection.tsx b/frontend/src/components/labwork/step/LabworkSelection.tsx
index aff75f7a53..8fefe2624f 100644
--- a/frontend/src/components/labwork/step/LabworkSelection.tsx
+++ b/frontend/src/components/labwork/step/LabworkSelection.tsx
@@ -4,10 +4,20 @@ import React, { useState, useCallback, useEffect, useMemo } from "react"
import { DEFAULT_SMALL_PAGE_SIZE } from "../../../constants"
import { useAppDispatch, useAppSelector, useSampleAndLibraryList } from "../../../hooks"
import { Protocol, Step } from "../../../models/frontend_models"
-import { updateSelectedSamplesAtStep, showSelectionChangedMessage, setSelectedSamples, unselectSamples } from "../../../modules/labworkSteps/actions"
+import {
+ updateSelectedSamplesAtStep,
+ showSelectionChangedMessage,
+ setSelectedSamples,
+ unselectSamples,
+} from "../../../modules/labworkSteps/actions"
import { LabworkStepSamples } from "../../../modules/labworkSteps/models"
-import { SampleAndLibrary, getColumnsForStep } from "../../WorkflowSamplesTable/ColumnSets"
-import WorkflowSamplesTable, { WorkflowSamplesTableProps } from "../../WorkflowSamplesTable/WorkflowSamplesTable"
+import {
+ SampleAndLibraryAndIdentity,
+ getColumnsForStep,
+} from "../../WorkflowSamplesTable/ColumnSets"
+import WorkflowSamplesTable, {
+ WorkflowSamplesTableProps,
+} from "../../WorkflowSamplesTable/WorkflowSamplesTable"
import { SampleColumnID } from "../../samples/SampleTableColumns"
import { FMSId } from "../../../models/fms_api_models"
import { selectCurrentPreferences } from "../../../modules/profiles/selectors"
@@ -15,97 +25,129 @@ import { selectCurrentPreferences } from "../../../modules/profiles/selectors"
const { Text } = Typography
export interface LabworkSelectionProps {
- stepSamples: LabworkStepSamples
- step: Step
- protocol: Protocol | undefined
- setSortByList: WorkflowSamplesTableProps['setSortByList']
+ stepSamples: LabworkStepSamples
+ step: Step
+ protocol: Protocol | undefined
+ setSortByList: WorkflowSamplesTableProps["setSortByList"]
}
-function samplesAndLibrariesToSampleIDs(sampleAndLibraries: SampleAndLibrary[]) {
- return sampleAndLibraries.reduce((sampleIDs, sampleAndLibrary) => {
- if (sampleAndLibrary.sample) {
- sampleIDs.push(sampleAndLibrary.sample.id)
- }
- return sampleIDs
- }, [] as FMSId[])
+function samplesAndLibrariesToSampleIDs(sampleAndLibraries: SampleAndLibraryAndIdentity[]) {
+ return sampleAndLibraries.reduce((sampleIDs, sampleAndLibrary) => {
+ if (sampleAndLibrary.sample) {
+ sampleIDs.push(sampleAndLibrary.sample.id)
+ }
+ return sampleIDs
+ }, [] as FMSId[])
}
-export function LabworkSelection({stepSamples, step, protocol, setSortByList}: LabworkSelectionProps) {
- const dispatch = useAppDispatch()
-
- const [pageSize, setPageSize] = useState(DEFAULT_SMALL_PAGE_SIZE)
- const defaultPageSize = useAppSelector(selectCurrentPreferences)['table.sample.page-limit']
- useEffect(() => {
- setPageSize(defaultPageSize)
- }, [defaultPageSize])
+export function LabworkSelection({
+ stepSamples,
+ step,
+ protocol,
+ setSortByList,
+}: LabworkSelectionProps) {
+ const dispatch = useAppDispatch()
- const [pageNumber, setPageNumber] = useState(1)
- const totalCount = stepSamples.selectedSamples.items.length
+ const [pageSize, setPageSize] = useState(DEFAULT_SMALL_PAGE_SIZE)
+ const defaultPageSize = useAppSelector(selectCurrentPreferences)["table.sample.page-limit"]
+ useEffect(() => {
+ setPageSize(defaultPageSize)
+ }, [defaultPageSize])
- const [samples, loading] = useSampleAndLibraryList(stepSamples.selectedSamples.items, pageSize * (pageNumber - 1), pageSize)
+ const [pageNumber, setPageNumber] = useState(1)
+ const totalCount = stepSamples.selectedSamples.items.length
- const onChangePageNumber = useCallback((pageNumber: number) => { setPageNumber(pageNumber) }, [])
- const onChangePageSize = useCallback((pageSize: number) => { setPageSize(pageSize) }, [])
+ const [samples, loading] = useSampleAndLibraryList(
+ stepSamples.selectedSamples.items,
+ pageSize * (pageNumber - 1),
+ pageSize,
+ )
- useEffect(() => {
- // order checked automatically
- dispatch(updateSelectedSamplesAtStep(step.id, stepSamples.selectedSamples.items))
- }, [dispatch, step.id, stepSamples.selectedSamples.items])
+ const onChangePageNumber = useCallback((pageNumber: number) => {
+ setPageNumber(pageNumber)
+ }, [])
+ const onChangePageSize = useCallback((pageSize: number) => {
+ setPageSize(pageSize)
+ }, [])
- // Columns for selected samples table
- const columnsForSelection = useMemo(() => {
- const columns = getColumnsForStep(step, protocol)
- // Make the Coordinates column sortable. We have to force the sorter to appear since
- // the selection table doesn't use column filters - otherwise, WorkflowSamplesTable would
- // take care of setting the column sortable.
- const coordsColumn = columns.find(col => col.columnID === SampleColumnID.COORDINATES)
- if (coordsColumn) {
- coordsColumn.sorter = true
- coordsColumn.key = SampleColumnID.COORDINATES
- coordsColumn.defaultSortOrder = 'ascend'
- coordsColumn.sortDirections = ['ascend', 'descend', 'ascend']
- }
- return columns
- }, [step, protocol])
+ useEffect(() => {
+ // order checked automatically
+ dispatch(updateSelectedSamplesAtStep(step.id, stepSamples.selectedSamples.items))
+ }, [dispatch, step.id, stepSamples.selectedSamples.items])
- const selection: WorkflowSamplesTableProps['selection'] = useMemo(() => ({
- selectedSampleIDs: stepSamples.selectedSamples.items,
- onSelectionChanged(selectedSamples) {
- const selectedSamplesInPage = samplesAndLibrariesToSampleIDs(selectedSamples)
- const unselectedSamples = samplesAndLibrariesToSampleIDs(samples).filter((id) => !selectedSamplesInPage.includes(id))
- dispatch(unselectSamples(step.id, unselectedSamples))
- }
- }), [dispatch, samples, step.id, stepSamples.selectedSamples.items])
+ // Columns for selected samples table
+ const columnsForSelection = useMemo(() => {
+ const columns = getColumnsForStep(step, protocol)
+ // Make the Coordinates column sortable. We have to force the sorter to appear since
+ // the selection table doesn't use column filters - otherwise, WorkflowSamplesTable would
+ // take care of setting the column sortable.
+ const coordsColumn = columns.find((col) => col.columnID === SampleColumnID.COORDINATES)
+ if (coordsColumn) {
+ coordsColumn.sorter = true
+ coordsColumn.key = SampleColumnID.COORDINATES
+ coordsColumn.defaultSortOrder = "ascend"
+ coordsColumn.sortDirections = ["ascend", "descend", "ascend"]
+ }
+ return columns
+ }, [step, protocol])
- return <>
- {stepSamples.showSelectionChangedWarning &&
- dispatch(showSelectionChangedMessage(step.id, false))}
- style={{ marginBottom: '1em' }}
- />
- }
- {/* Selection table does not allow filtering or sorting.*/}
- {/* Also, we don't handle pagination for selected samples so we are required to
+ const selection: WorkflowSamplesTableProps["selection"] = useMemo(
+ () => ({
+ selectedSampleIDs: stepSamples.selectedSamples.items,
+ onSelectionChanged(selectedSamples) {
+ const selectedSamplesInPage = samplesAndLibrariesToSampleIDs(selectedSamples)
+ const unselectedSamples = samplesAndLibrariesToSampleIDs(samples).filter(
+ (id) => !selectedSamplesInPage.includes(id),
+ )
+ dispatch(unselectSamples(step.id, unselectedSamples))
+ },
+ }),
+ [dispatch, samples, step.id, stepSamples.selectedSamples.items],
+ )
+
+ return (
+ <>
+ {stepSamples.showSelectionChangedWarning && (
+ dispatch(showSelectionChangedMessage(step.id, false))}
+ style={{ marginBottom: "1em" }}
+ />
+ )}
+ {/* Selection table does not allow filtering or sorting.*/}
+ {/* Also, we don't handle pagination for selected samples so we are required to
load all of the selected samples and libraries for the table to work.
*/}
-
- Samples are automatically sorted by container name and then by coordinate.
-
- >
+
+
+
+
+ Samples are automatically sorted by{" "}
+
+ container name
+ {" "}
+ and then by{" "}
+
+ coordinate
+
+ .
+
+
+ >
+ )
}
-export default LabworkSelection
\ No newline at end of file
+export default LabworkSelection
diff --git a/frontend/src/components/studySamples/StudyStepSamplesTable.tsx b/frontend/src/components/studySamples/StudyStepSamplesTable.tsx
index 5a403cb18d..31206e8cc8 100644
--- a/frontend/src/components/studySamples/StudyStepSamplesTable.tsx
+++ b/frontend/src/components/studySamples/StudyStepSamplesTable.tsx
@@ -1,19 +1,40 @@
-import React, { useCallback, useMemo } from 'react'
-import { useAppDispatch, useAppSelector } from '../../hooks'
-import { FMSId } from '../../models/fms_api_models'
-import { Protocol } from '../../models/frontend_models'
-import { clearFilters, refreshStudySamples, setStudyStepFilter, setStudyStepFilterOptions, setStudyStepPageNumber, setStudyStepPageSize, setStudyStepSortOrder } from '../../modules/studySamples/actions'
-import { StudySampleStep, StudyStepSamplesTableState, StudyUXStepSettings } from '../../modules/studySamples/models'
-import { selectProtocolsByID, selectStepsByID } from '../../selectors'
-import { SampleAndLibrary, getColumnsForStudySamplesStep } from '../WorkflowSamplesTable/ColumnSets'
-import { LIBRARY_COLUMN_FILTERS, SAMPLE_NEXT_STEP_BY_STUDY_LIBRARY_FILTER_KEYS } from '../libraries/LibraryTableColumns'
-import { SAMPLE_COLUMN_FILTERS, SAMPLE_NEXT_STEP_BY_STUDY_FILTER_KEYS } from '../samples/SampleTableColumns'
-import WorkflowSamplesTable from '../WorkflowSamplesTable/WorkflowSamplesTable'
-import { FilterDescription, FilterValue, SortBy } from '../../models/paged_items'
-import { Popconfirm, Button, notification } from 'antd'
-import api from '../../utils/api'
-import { IdentifiedTableColumnType } from '../pagedItemsTable/PagedItemsColumns'
-import { DEFAULT_SMALL_PAGINATION_LIMIT } from '../../config'
+import React, { useCallback, useMemo } from "react"
+import { useAppDispatch, useAppSelector } from "../../hooks"
+import { FMSId } from "../../models/fms_api_models"
+import { Protocol } from "../../models/frontend_models"
+import {
+ clearFilters,
+ refreshStudySamples,
+ setStudyStepFilter,
+ setStudyStepFilterOptions,
+ setStudyStepPageNumber,
+ setStudyStepPageSize,
+ setStudyStepSortOrder,
+} from "../../modules/studySamples/actions"
+import {
+ StudySampleStep,
+ StudyStepSamplesTableState,
+ StudyUXStepSettings,
+} from "../../modules/studySamples/models"
+import { selectProtocolsByID, selectStepsByID } from "../../selectors"
+import {
+ SampleAndLibraryAndIdentity,
+ getColumnsForStudySamplesStep,
+} from "../WorkflowSamplesTable/ColumnSets"
+import {
+ LIBRARY_COLUMN_FILTERS,
+ SAMPLE_NEXT_STEP_BY_STUDY_LIBRARY_FILTER_KEYS,
+} from "../libraries/LibraryTableColumns"
+import {
+ SAMPLE_COLUMN_FILTERS,
+ SAMPLE_NEXT_STEP_BY_STUDY_FILTER_KEYS,
+} from "../samples/SampleTableColumns"
+import WorkflowSamplesTable from "../WorkflowSamplesTable/WorkflowSamplesTable"
+import { FilterDescription, FilterValue, SortBy } from "../../models/paged_items"
+import { Popconfirm, Button, notification } from "antd"
+import api from "../../utils/api"
+import { IdentifiedTableColumnType } from "../pagedItemsTable/PagedItemsColumns"
+import { DEFAULT_SMALL_PAGINATION_LIMIT } from "../../config"
interface StudyStepSamplesTableProps {
studyID: FMSId
@@ -22,8 +43,12 @@ interface StudyStepSamplesTableProps {
settings?: StudyUXStepSettings
}
-function StudyStepSamplesTable({ studyID, step, tableState, settings }: StudyStepSamplesTableProps) {
-
+function StudyStepSamplesTable({
+ studyID,
+ step,
+ tableState,
+ settings,
+}: StudyStepSamplesTableProps) {
const dispatch = useAppDispatch()
const protocolsByID = useAppSelector(selectProtocolsByID)
const stepsByID = useAppSelector(selectStepsByID)
@@ -31,73 +56,96 @@ function StudyStepSamplesTable({ studyID, step, tableState, settings }: StudySte
const pageSize = settings?.pageSize ?? DEFAULT_SMALL_PAGINATION_LIMIT
const pageNumber = tableState?.pageNumber ?? 1
- const onChangePageNumber = useCallback((pageNumber: number) => { dispatch(setStudyStepPageNumber(studyID, step.stepOrderID, 'ready', pageNumber)) }, [dispatch, studyID, step.stepOrderID])
- const onChangePageSize = useCallback((pageSize: number) => { dispatch(setStudyStepPageSize(studyID, step.stepOrderID, pageSize)) }, [dispatch, studyID, step.stepOrderID])
+ const onChangePageNumber = useCallback(
+ (pageNumber: number) => {
+ dispatch(setStudyStepPageNumber(studyID, step.stepOrderID, "ready", pageNumber))
+ },
+ [dispatch, studyID, step.stepOrderID],
+ )
+ const onChangePageSize = useCallback(
+ (pageSize: number) => {
+ dispatch(setStudyStepPageSize(studyID, step.stepOrderID, pageSize))
+ },
+ [dispatch, studyID, step.stepOrderID],
+ )
const setFilter = useCallback(
(filterKey: string, value: FilterValue, description: FilterDescription) => {
dispatch(setStudyStepFilter(studyID, step.stepOrderID, description, value))
- }
- , [studyID, step, dispatch])
+ },
+ [studyID, step, dispatch],
+ )
const setFilterOptions = useCallback(
(filterKey: string, propertyName: string, value: boolean, description: FilterDescription) => {
- dispatch(setStudyStepFilterOptions(studyID, step.stepOrderID, description, { [propertyName]: value }))
- }
- , [dispatch, studyID, step])
+ dispatch(
+ setStudyStepFilterOptions(studyID, step.stepOrderID, description, {
+ [propertyName]: value,
+ }),
+ )
+ },
+ [dispatch, studyID, step],
+ )
const setSortBy = useCallback(
(sortBy: SortBy) => {
dispatch(setStudyStepSortOrder(studyID, step.stepOrderID, sortBy))
- }
- , [studyID, step, dispatch])
+ },
+ [studyID, step, dispatch],
+ )
const protocol: Protocol | undefined = protocolsByID[step.protocolID]
const stepDefinition = stepsByID[step.stepID]
- const actionColumn = useMemo(() => ({
- columnID: 'Action',
- title: 'Action',
- dataIndex: ['sample', 'id'],
- width: 100,
- render: (_: any, { sample }: SampleAndLibrary) => {
- return {
- if (!sample) return;
- const REMOVE_NOTIFICATION_KEY = `StudyStepSamplesTable.remove-${studyID}-${step.stepID}-${sample.id}`
- notification.info({
- message: `Removing sample '${sample?.name}' from step '${step.stepName}'`,
- key: REMOVE_NOTIFICATION_KEY
- })
- await dispatch(api.sampleNextStepByStudy.remove(step.ready.sampleNextStepByID[sample.id]))
- await dispatch(refreshStudySamples(studyID))
- notification.destroy(REMOVE_NOTIFICATION_KEY)
- }}
- disabled={!sample}
- placement={'topLeft'}
- >
-
-
- }
- }), [dispatch, step.ready.sampleNextStepByID, step.stepID, step.stepName, studyID])
+ const actionColumn = useMemo(
+ () => ({
+ columnID: "Action",
+ title: "Action",
+ dataIndex: ["sample", "id"],
+ width: 100,
+ render: (_: any, { sample }: SampleAndLibraryAndIdentity) => {
+ return (
+ {
+ if (!sample) return
+ const REMOVE_NOTIFICATION_KEY = `StudyStepSamplesTable.remove-${studyID}-${step.stepID}-${sample.id}`
+ notification.info({
+ message: `Removing sample '${sample?.name}' from step '${step.stepName}'`,
+ key: REMOVE_NOTIFICATION_KEY,
+ })
+ await dispatch(
+ api.sampleNextStepByStudy.remove(step.ready.sampleNextStepByID[sample.id]),
+ )
+ await dispatch(refreshStudySamples(studyID))
+ notification.destroy(REMOVE_NOTIFICATION_KEY)
+ }}
+ disabled={!sample}
+ placement={"topLeft"}
+ >
+
+
+ )
+ },
+ }),
+ [dispatch, step.ready.sampleNextStepByID, step.stepID, step.stepName, studyID],
+ )
- const columns: IdentifiedTableColumnType[] = useMemo(() => {
- if (stepDefinition) { // missing protocol leads to default columns
+ const columns: IdentifiedTableColumnType[] = useMemo(() => {
+ if (stepDefinition) {
+ // missing protocol leads to default columns
// Same columns as labwork, but we don't want the Project column, since the user
// is already in the project details page.
- return [
- ...getColumnsForStudySamplesStep(stepDefinition, protocol),
- actionColumn,
- ]
+ return [...getColumnsForStudySamplesStep(stepDefinition, protocol), actionColumn]
} else {
return []
}
}, [actionColumn, protocol, stepDefinition])
const localClearFilters = useCallback(() => {
- if (clearFilters)
- dispatch(clearFilters(studyID, step.stepOrderID))
+ if (clearFilters) dispatch(clearFilters(studyID, step.stepOrderID))
}, [dispatch, step.stepOrderID, studyID])
return (
@@ -107,15 +155,24 @@ function StudyStepSamplesTable({ studyID, step, tableState, settings }: StudySte
samples={step.ready.samples}
columns={columns}
filterDefinitions={{ ...SAMPLE_COLUMN_FILTERS, ...LIBRARY_COLUMN_FILTERS }}
- filterKeys={{ ...SAMPLE_NEXT_STEP_BY_STUDY_FILTER_KEYS, ...SAMPLE_NEXT_STEP_BY_STUDY_LIBRARY_FILTER_KEYS }}
+ filterKeys={{
+ ...SAMPLE_NEXT_STEP_BY_STUDY_FILTER_KEYS,
+ ...SAMPLE_NEXT_STEP_BY_STUDY_LIBRARY_FILTER_KEYS,
+ }}
filters={settings?.filters ?? {}}
setFilter={setFilter}
setFilterOptions={setFilterOptions}
setSortBy={setSortBy}
- pagination={{ pageNumber, pageSize, totalCount: step.ready.count, onChangePageNumber, onChangePageSize }}
+ pagination={{
+ pageNumber,
+ pageSize,
+ totalCount: step.ready.count,
+ onChangePageNumber,
+ onChangePageSize,
+ }}
loading={tableState?.isFetching ?? true}
/>
)
}
-export default StudyStepSamplesTable
\ No newline at end of file
+export default StudyStepSamplesTable