From 03050a55703b345c60e0551f12f7ec6df51a6cfe Mon Sep 17 00:00:00 2001 From: Alex Pickering Date: Mon, 16 Sep 2024 14:13:43 -0700 Subject: [PATCH 1/7] init sce upload; rename seurat pipeline to obj2s Signed-off-by: Alex Pickering --- .../DownloadDataButton.test.jsx | 2 +- .../LaunchAnalysisButton.test.jsx | 8 +-- .../utils/experimentUpdatesHandler.test.js | 14 ++--- src/components/ContentWrapper.jsx | 52 +++++++++---------- src/components/GEM2SLoadingScreen.jsx | 8 +-- .../SubsetCellSetsOperation.jsx | 4 +- .../data-management/FileUploadModal.jsx | 21 ++++---- .../data-management/LaunchAnalysisButton.jsx | 12 ++--- .../data-management/SamplesTable.jsx | 6 +-- .../metadata/AddMetadataButton.jsx | 4 +- src/redux/actions/pipeline/index.js | 4 +- .../pipeline/{runSeurat.js => runObj2s.js} | 4 +- src/utils/constants.js | 4 ++ .../calculatePipelinesRerunStatus.js | 8 +-- src/utils/endUserMessages.jsx | 8 +-- src/utils/experimentUpdatesHandler.js | 8 +-- .../downloadProcessedMatrix.js | 8 +-- src/utils/sampleFileType.js | 4 +- src/utils/upload/fileInspector.js | 4 +- src/utils/upload/fileUploadUtils.js | 31 +++++++++++ src/utils/upload/sampleValidators.js | 5 +- src/utils/upload/validateObj2s.js | 5 ++ src/utils/upload/validateSeurat.js | 5 -- 23 files changed, 134 insertions(+), 95 deletions(-) rename src/redux/actions/pipeline/{runSeurat.js => runObj2s.js} (89%) create mode 100644 src/utils/upload/validateObj2s.js delete mode 100644 src/utils/upload/validateSeurat.js diff --git a/src/__test__/components/data-management/DownloadDataButton.test.jsx b/src/__test__/components/data-management/DownloadDataButton.test.jsx index e82f0f6966..69125cfda4 100644 --- a/src/__test__/components/data-management/DownloadDataButton.test.jsx +++ b/src/__test__/components/data-management/DownloadDataButton.test.jsx @@ -230,7 +230,7 @@ describe('DownloadDataButton', () => { }); expect(pushNotificationMessage).toHaveBeenCalledTimes(1); - expect(pushNotificationMessage).toHaveBeenCalledWith('error', endUserMessages.ERROR_DOWNLOADING_SEURAT_OBJECT); + expect(pushNotificationMessage).toHaveBeenCalledWith('error', endUserMessages.ERROR_DOWNLOADING_OBJ2S); }); it('Has options disabled if backend status is still loading', async () => { diff --git a/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx b/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx index 5f417900e2..2f07e00238 100644 --- a/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx +++ b/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx @@ -8,7 +8,7 @@ import { act } from 'react-dom/test-utils'; import { screen, render, waitFor, fireEvent, } from '@testing-library/react'; -import { runGem2s, runSeurat } from 'redux/actions/pipeline'; +import { runGem2s, runObj2s } from 'redux/actions/pipeline'; import PipelineStatus from 'utils/pipelineStatusValues'; import { sampleTech } from 'utils/constants'; @@ -25,7 +25,7 @@ import '__test__/test-utils/setupTests'; jest.mock('redux/actions/experimentSettings/updateExperimentInfo', () => jest.fn().mockReturnValue({ type: 'UPDATE_EXPERIMENT_INFO' })); jest.mock('redux/actions/pipeline', () => ({ runGem2s: jest.fn().mockReturnValue({ type: 'RUN_GEM2S' }), - runSeurat: jest.fn().mockReturnValue({ type: 'RUN_SEURAT' }), + runObj2s: jest.fn().mockReturnValue({ type: 'RUN_OBJ2S' }), })); const mockNavigateTo = jest.fn(); @@ -495,7 +495,7 @@ describe('LaunchAnalysisButton', () => { expect(mockNavigateTo).toHaveBeenCalled(); }); - it('Does dispatch a request to runSeurat for an unprocessed experiment', async () => { + it('Does dispatch a request to runObj2s for an unprocessed experiment', async () => { calculateGem2sRerunStatus.mockReturnValue(rerunState); calculateQCRerunStatus.mockReturnValue(notRerunState); @@ -529,6 +529,6 @@ describe('LaunchAnalysisButton', () => { fireEvent.click(screen.getByText('Yes')); expect(runGem2s).not.toHaveBeenCalled(); - expect(runSeurat).toHaveBeenCalled(); + expect(runObj2s).toHaveBeenCalled(); }); }); diff --git a/src/__test__/utils/experimentUpdatesHandler.test.js b/src/__test__/utils/experimentUpdatesHandler.test.js index 5abc168a93..698cd1f317 100644 --- a/src/__test__/utils/experimentUpdatesHandler.test.js +++ b/src/__test__/utils/experimentUpdatesHandler.test.js @@ -94,8 +94,8 @@ const mockWorkResponseUpdate = { }, }; -const mockSeuratUpdate = { - type: updateTypes.SEURAT, +const mockObj2sUpdate = { + type: updateTypes.OBJ2S, item: { processingConfig: { mockProcessingConfig: 'mockProcessingConfig', @@ -131,8 +131,8 @@ describe('ExperimentUpdatesHandler', () => { expect(pushNotificationMessage).not.toHaveBeenCalled(); }); - it('Triggers properly for SEURAT updates ', () => { - const mockUpdate = mockSeuratUpdate; + it('Triggers properly for OBJ2S updates ', () => { + const mockUpdate = mockObj2sUpdate; triggerExperimentUpdate(mockUpdate); @@ -145,8 +145,8 @@ describe('ExperimentUpdatesHandler', () => { expect(pushNotificationMessage).not.toHaveBeenCalled(); }); - it('Triggers properly for SEURAT updates ', () => { - const mockUpdate = mockSeuratUpdate; + it('Triggers properly for OBJ2S updates ', () => { + const mockUpdate = mockObj2sUpdate; triggerExperimentUpdate(mockUpdate); @@ -160,7 +160,7 @@ describe('ExperimentUpdatesHandler', () => { it('Loads cell sets if Seurat pipeline completes ', () => { const mockUpdate = { - ...mockSeuratUpdate, + ...mockObj2sUpdate, status: { seurat: { status: 'SUCCEEDED', diff --git a/src/components/ContentWrapper.jsx b/src/components/ContentWrapper.jsx index e6423d6ad0..de4bd62f5c 100644 --- a/src/components/ContentWrapper.jsx +++ b/src/components/ContentWrapper.jsx @@ -33,7 +33,7 @@ import { loadUser } from 'redux/actions/user'; import { loadBackendStatus } from 'redux/actions/backendStatus'; import { isBrowser, privacyPolicyIsNotAccepted } from 'utils/deploymentInfo'; -import { modules } from 'utils/constants'; +import { modules, obj2sTechs } from 'utils/constants'; import { useAppRouter } from 'utils/AppRouteProvider'; import experimentUpdatesHandler from 'utils/experimentUpdatesHandler'; import integrationTestConstants from 'utils/integrationTestConstants'; @@ -105,15 +105,15 @@ const ContentWrapper = (props) => { const gem2sRunning = gem2sStatusKey === 'RUNNING'; const gem2sRunningError = backendErrors.includes(gem2sStatusKey); const completedGem2sSteps = backendStatus?.gem2s?.completedSteps; - const seuratStatusKey = backendStatus?.seurat?.status; + const obj2sStatusKey = backendStatus?.seurat?.status; - const isSeurat = seuratStatusKey && selectedTechnology === 'seurat'; + const isObj2s = obj2sStatusKey && obj2sTechs.includes(selectedTechnology); const [pipelinesRerunStatus, setPipelinesRerunStatus] = useState(null); - const seuratRunning = seuratStatusKey === 'RUNNING' && isSeurat; - const seuratRunningError = backendErrors.includes(seuratStatusKey) && isSeurat; - const completedSeuratSteps = backendStatus?.seurat?.completedSteps; - const seuratComplete = (seuratStatusKey === pipelineStatusValues.SUCCEEDED) && isSeurat; + const obj2sRunning = obj2sStatusKey === 'RUNNING' && isObj2s; + const obj2sRunningError = backendErrors.includes(obj2sStatusKey) && isObj2s; + const completedObj2sSteps = backendStatus?.seurat?.completedSteps; + const obj2sComplete = (obj2sStatusKey === pipelineStatusValues.SUCCEEDED) && isObj2s; const waitingForQcToLaunch = gem2sStatusKey === pipelineStatusValues.SUCCEEDED && qcStatusKey === pipelineStatusValues.NOT_CREATED; // This is used to prevent a race condition where the page would start loading immediately @@ -154,7 +154,7 @@ const ContentWrapper = (props) => { if (!experiment || !backendStatus) return; // The value of backend status is null for new experiments that have never run - const setupPipeline = isSeurat ? 'seurat' : 'gem2s'; + const setupPipeline = isObj2s ? 'seurat' : 'gem2s'; const { pipeline: qcBackendStatus, [setupPipeline]: setupBackendStatus, } = backendStatus ?? {}; @@ -169,7 +169,7 @@ const ContentWrapper = (props) => { setupBackendStatus, qcBackendStatus, experiment, - isSeurat, + isObj2s, ), ); }, [backendStatus, experiment, samples]); @@ -187,16 +187,16 @@ const ContentWrapper = (props) => { }); const gem2sNotCreated = checkEveryIsValue( - [gem2sStatusKey, seuratStatusKey], pipelineStatusValues.NOT_CREATED, + [gem2sStatusKey, obj2sStatusKey], pipelineStatusValues.NOT_CREATED, ); - const getSeuratStatus = () => { - if (seuratRunningError) { + const getObj2sStatus = () => { + if (obj2sRunningError) { const errorMessage = pipelineErrorUserMessages[backendStatus?.seurat?.error?.error]; - return getStatusObject('seurat', 'error', errorMessage); + return getStatusObject('obj2s', 'error', errorMessage); } - if (seuratRunning) { - return getStatusObject('seurat', 'running', null, completedSeuratSteps); + if (obj2sRunning) { + return getStatusObject('obj2s', 'running', null, completedObj2sSteps); } return null; }; @@ -225,8 +225,8 @@ const ContentWrapper = (props) => { }; const getCurrentStatusScreen = () => { - if (isSeurat) { - return getSeuratStatus(); + if (isObj2s) { + return getObj2sStatus(); } return getGem2sStatus() || getQcStatus(); }; @@ -309,7 +309,7 @@ const ContentWrapper = (props) => { name: 'Data Management', disableIfNoExperiment: false, disabledByPipelineStatus: true, - disabledIfSeuratComplete: false, + disabledIfObj2sComplete: false, }, { module: modules.DATA_PROCESSING, @@ -317,7 +317,7 @@ const ContentWrapper = (props) => { name: 'Data Processing', disableIfNoExperiment: true, disabledByPipelineStatus: false, - disabledIfSeuratComplete: true, + disabledIfObj2sComplete: true, }, { module: modules.DATA_EXPLORATION, @@ -325,7 +325,7 @@ const ContentWrapper = (props) => { name: 'Data Exploration', disableIfNoExperiment: true, disabledByPipelineStatus: true, - disabledIfSeuratComplete: false, + disabledIfObj2sComplete: false, }, { module: modules.PLOTS_AND_TABLES, @@ -333,7 +333,7 @@ const ContentWrapper = (props) => { name: 'Plots and Tables', disableIfNoExperiment: true, disabledByPipelineStatus: true, - disabledIfSeuratComplete: false, + disabledIfObj2sComplete: false, }, ]; @@ -363,7 +363,7 @@ const ContentWrapper = (props) => { ); } - if (seuratComplete && currentModule === modules.DATA_PROCESSING) { + if (obj2sComplete && currentModule === modules.DATA_PROCESSING) { navigateTo(modules.DATA_EXPLORATION, { experimentId: routeExperimentId }); return <>; } @@ -377,7 +377,7 @@ const ContentWrapper = (props) => { }; const menuItemRender = ({ - module, icon, name, disableIfNoExperiment, disabledByPipelineStatus, disabledIfSeuratComplete, + module, icon, name, disableIfNoExperiment, disabledByPipelineStatus, disabledIfObj2sComplete, }) => { const needRerunPipeline = pipelinesRerunStatus === null || pipelinesRerunStatus.rerun; @@ -387,7 +387,7 @@ const ContentWrapper = (props) => { const pipelineStatusDisable = disabledByPipelineStatus && ( backendError || gem2sRunning || gem2sRunningError || waitingForQcToLaunch || qcRunning || qcRunningError - || seuratRunning || seuratRunningError + || obj2sRunning || obj2sRunningError ); const { @@ -398,14 +398,14 @@ const ContentWrapper = (props) => { const nonExperimentModule = ![DATA_EXPLORATION, DATA_MANAGEMENT, DATA_PROCESSING, PLOTS_AND_TABLES] .includes(currentModule) && disableIfNoExperiment; - const seuratCompleteDisable = disabledIfSeuratComplete && seuratComplete; + const obj2sCompleteDisable = disabledIfObj2sComplete && obj2sComplete; return { key: module, icon, label: name, disabled: notProcessedExperimentDisable || pipelineStatusDisable - || seuratCompleteDisable || nonExperimentModule, + || obj2sCompleteDisable || nonExperimentModule, onClick: () => navigateTo( module, { experimentId: currentExperimentId }, diff --git a/src/components/GEM2SLoadingScreen.jsx b/src/components/GEM2SLoadingScreen.jsx index dc509b18aa..6ea23c3d4b 100644 --- a/src/components/GEM2SLoadingScreen.jsx +++ b/src/components/GEM2SLoadingScreen.jsx @@ -20,9 +20,9 @@ const pipelineStepsInfoByType = { 'Uploading completed data', ], - seurat: [ - 'Downloading RDS file', - 'Processing Seurat object', + obj2s: [ + 'Downloading project data', + 'Processing object', 'Uploading completed data', ], }; @@ -168,7 +168,7 @@ const GEM2SLoadingScreen = (props) => { GEM2SLoadingScreen.propTypes = { pipelineStatus: PropTypes.oneOf(['error', 'running', 'toBeRun', 'subsetting']).isRequired, - pipelineType: PropTypes.oneOf(['gem2s', 'seurat']).isRequired, + pipelineType: PropTypes.oneOf(['gem2s', 'obj2s']).isRequired, completedSteps: PropTypes.array, experimentId: PropTypes.string, experimentName: PropTypes.string, diff --git a/src/components/data-exploration/cell-sets-tool/SubsetCellSetsOperation.jsx b/src/components/data-exploration/cell-sets-tool/SubsetCellSetsOperation.jsx index 9659e726b6..63c0ebf707 100644 --- a/src/components/data-exploration/cell-sets-tool/SubsetCellSetsOperation.jsx +++ b/src/components/data-exploration/cell-sets-tool/SubsetCellSetsOperation.jsx @@ -7,7 +7,7 @@ import { Tooltip, Button } from 'antd'; import { PieChartOutlined } from '@ant-design/icons'; import SubsetCellSetsModal from 'components/data-exploration/cell-sets-tool/SubsetCellSetsModal'; -import { sampleTech } from 'utils/constants'; +import { obj2sTechs } from 'utils/constants'; const SubsetCellSetsOperation = (props) => { const { onCreate } = props; @@ -23,7 +23,7 @@ const SubsetCellSetsOperation = (props) => {