Skip to content

Commit

Permalink
Merge branch 'master' into cache-disable
Browse files Browse the repository at this point in the history
  • Loading branch information
ivababukova authored Nov 29, 2023
2 parents f4665e0 + 97c3fd1 commit 8f11feb
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ exports[`DownloadDataButton Downloads processed matrix properly 1`] = `
[
"testae48e318dab9a1bd0bexperiment-0",
{
"embeddingMethod": "umap",
"name": "DownloadAnnotSeuratObject",
},
[Function],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { initialPlotConfigStates } from 'redux/reducers/componentConfig/initialS
import { generateDataProcessingPlotUuid } from 'utils/generateCustomPlotUuid';
import CellSizeDistribution from 'components/data-processing/CellSizeDistribution/CellSizeDistribution';
import CalculationConfig from 'components/data-processing/CellSizeDistribution/CalculationConfig';
import SliderWithInput from 'components/SliderWithInput';
import generateExperimentSettingsMock from '../../../test-utils/experimentSettings.mock';

import filterStatisticsMock from '../../../test-utils/plotData.mock';
Expand Down Expand Up @@ -147,4 +148,31 @@ describe('CellSizeDistribution', () => {
expect(plots.length).toEqual(3);
expect(tables.length).toEqual(1);
});
it('Disables bin step slider when plot type is knee plot', () => {
const modifiedWithData = {
...withData,
componentConfig: {
...withData.componentConfig,
plotType: 'kneePlot',
},
};

const store = mockStore(modifiedWithData);

const component = mount(
<Provider store={store}>
<CellSizeDistribution
experimentId={experimentId}
sampleId={sampleId}
sampleIds={sampleIds}
onConfigChange={() => { }}
/>
</Provider>,
);

const page = component.find(CellSizeDistribution).at(0);
const calculationConfig = page.find(CalculationConfig);
const sliderWithInput = calculationConfig.find(SliderWithInput);
expect(sliderWithInput.props().disabled).toBe(true);
});
});
14 changes: 14 additions & 0 deletions src/__test__/redux/reducers/samplesReducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,4 +398,18 @@ describe('samplesReducer', () => {

expect(newState).toMatchSnapshot();
});

it('Sample file update doesnt change anything if the sample no longer exists', () => {
const newState = samplesReducer(initialState, {
type: SAMPLES_FILE_UPDATE,
payload: {
sampleUuid: mockUuid1,
fileName,
fileDiff: mockFile,
lastModified: 'newLastModified',
},
});

expect(newState).toEqual(initialState);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl",
},
{
Expand All @@ -243,6 +244,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl",
},
{
Expand All @@ -252,6 +254,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl",
},
]
Expand Down Expand Up @@ -401,6 +404,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl",
},
{
Expand All @@ -410,6 +414,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl",
},
{
Expand All @@ -419,6 +424,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl",
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl1",
},
{
Expand All @@ -18,6 +19,7 @@ exports[`processUpload Uploads and updates redux correctly when there are no err
},
"method": "put",
"onUploadProgress": [Function],
"signal": AbortSignal {},
"url": "theSignedUrl2",
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const MIN_CELL_SIZE_PLACEHOLDER = 10800;

const CellSizeDistributionConfig = (props) => {
const {
config, disabled, updateSettings, highestUmi,
config, disabled, updateSettings, highestUmi, plotType,
} = props;

const withinRange = (cellSize) => Math.max(Math.min(cellSize, highestUmi), 0);
Expand Down Expand Up @@ -54,7 +54,7 @@ const CellSizeDistributionConfig = (props) => {
onUpdate={(value) => {
updateSettings({ binStep: value });
}}
disabled={disabled}
disabled={disabled || plotType === 'kneePlot'}
/>
</Form.Item>
</>
Expand All @@ -65,12 +65,14 @@ CellSizeDistributionConfig.defaultProps = {
config: {},
disabled: false,
highestUmi: null,
plotType: null,
};
CellSizeDistributionConfig.propTypes = {
updateSettings: PropTypes.func,
config: PropTypes.object,
disabled: PropTypes.bool,
highestUmi: PropTypes.number,
plotType: PropTypes.string,
};

export default CellSizeDistributionConfig;
5 changes: 4 additions & 1 deletion src/redux/actions/samples/createSampleFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const createSampleFile = (
sampleId,
type,
fileForApiV1,
abortController,
) => async (dispatch) => {
const updatedAt = dayjs().toISOString();

Expand All @@ -30,8 +31,10 @@ const createSampleFile = (
lastModified: updatedAt,
fileName: fileNameForApiV1[type],
fileDiff: {
upload: { status: UploadStatus.UPLOADING },
...fileForApiV1,
upload: {
status: UploadStatus.UPLOADING, progress: 0, abortController,
},
},
},
});
Expand Down
13 changes: 10 additions & 3 deletions src/redux/actions/samples/createSamples.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import { defaultSampleOptions, sampleTemplate } from 'redux/reducers/samples/ini
import { sampleTech } from 'utils/constants';
import UploadStatus from 'utils/upload/UploadStatus';

import fileNameForApiV1 from 'utils/upload/fileNameForApiV1';
import getFileTypeV2 from 'utils/getFileTypeV2';

// If the sample name of new samples coincides with already existing
// ones we should not create new samples,
// just reuse their sampleIds and upload the new files
Expand Down Expand Up @@ -115,9 +118,13 @@ const createSamples = (
options,
metadata: experiment?.metadataKeys
.reduce((acc, curr) => ({ ...acc, [curr]: METADATA_DEFAULT_VALUE }), {}) || {},
files: Object.values(files).reduce(((acc, curr) => (
{ ...acc, [curr.name]: { upload: { status: UploadStatus.UPLOADING } } }
)), {}),
files: Object.values(files).reduce(((acc, curr) => {
const fileType = fileNameForApiV1[getFileTypeV2(curr.name, sampleTechnology)];

return (
{ ...acc, [fileType]: { upload: { status: UploadStatus.UPLOADING } } }
);
}), {}),
}));

dispatch({
Expand Down
14 changes: 5 additions & 9 deletions src/redux/actions/samples/deleteSamples.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@ import endUserMessages from 'utils/endUserMessages';
import fetchAPI from 'utils/http/fetchAPI';
import handleError from 'utils/http/handleError';

const cancelUploads = async (files) => {
const promises = Object.values(files).map(({ upload }) => {
if (upload?.amplifyPromise) {
// return Storage.cancel(upload.amplifyPromise);
}
return Promise.resolve();
const cancelUploads = (files) => {
Object.values(files).forEach((file) => {
// eslint-disable-next-line no-unused-expressions
file.upload?.abortController?.abort();
});

return Promise.all(promises);
};

const deleteSamples = (
Expand All @@ -34,7 +30,7 @@ const deleteSamples = (
acc[samples[sampleUuid].experimentId] = [];
}

await cancelUploads(files);
cancelUploads(files);

return {
...acc,
Expand Down
6 changes: 6 additions & 0 deletions src/redux/reducers/samples/samplesFileUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ const samplesFileUpdate = (state, action) => {
sampleUuid, fileName, fileDiff, lastModified,
} = action.payload;

// There's a possible race condition where a file update can reach this place
// after a sample is deleted and there's a crash. This check is in place to avoid that error.
if (_.isNil(state[sampleUuid])) {
return state;
}

const oldFile = state[sampleUuid].files?.[fileName];
let newFile = fileDiff;

Expand Down
1 change: 1 addition & 0 deletions src/utils/extraActionCreators/downloadProcessedMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const downloadProcessedMatrix = (experimentId) => async (dispatch, getState) =>
// the embeddingETag is added by the API to this body
const body = {
name: taskName,
embeddingMethod,
};

const timeout = getTimeoutForWorkerTask(getState(), taskName);
Expand Down
18 changes: 15 additions & 3 deletions src/utils/upload/processMultipartUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import axios from 'axios';
const FILE_CHUNK_SIZE = 10000000;
const MAX_RETRIES = 2;

const putPartInS3 = async (blob, signedUrl, onUploadProgress, currentRetry = 0) => {
const putPartInS3 = async (
blob, signedUrl, onUploadProgress, currentRetry = 0, abortController = null,
) => {
try {
return await axios.request({
method: 'put',
data: blob,
url: signedUrl,
signal: abortController.signal,
headers: {
'Content-Type': 'application/octet-stream',
},
Expand All @@ -23,7 +26,9 @@ const putPartInS3 = async (blob, signedUrl, onUploadProgress, currentRetry = 0)
}
};

const processMultipartUpload = async (file, signedUrls, createOnUploadProgressForPart) => {
const processMultipartUpload = async (
file, signedUrls, createOnUploadProgressForPart, abortController,
) => {
const promises = [];

signedUrls.forEach((signedUrl, index) => {
Expand All @@ -33,7 +38,14 @@ const processMultipartUpload = async (file, signedUrls, createOnUploadProgressFo
? file.fileObject.slice(start, end)
: file.fileObject.slice(start);

const req = putPartInS3(blob, signedUrl, createOnUploadProgressForPart(index));
const req = putPartInS3(
blob,
signedUrl,
createOnUploadProgressForPart(index),
0,
abortController,
);

promises.push(req);
});

Expand Down
12 changes: 8 additions & 4 deletions src/utils/upload/processUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import endUserMessages from 'utils/endUserMessages';
import pushNotificationMessage from 'utils/pushNotificationMessage';

const prepareAndUploadFileToS3 = async (
file, uploadUrlParams, type, onStatusUpdate = () => { },
file, uploadUrlParams, type, onStatusUpdate = () => { }, abortController = null,
) => {
let parts = null;
const { signedUrls, uploadId, fileId } = uploadUrlParams;
Expand All @@ -34,7 +34,9 @@ const prepareAndUploadFileToS3 = async (
onStatusUpdate(UploadStatus.UPLOADING, percentProgress);
};
try {
parts = await processMultipartUpload(file, signedUrls, createOnUploadProgressForPart);
parts = await processMultipartUpload(
file, signedUrls, createOnUploadProgressForPart, abortController,
);
} catch (e) {
onStatusUpdate(UploadStatus.UPLOAD_ERROR);
return;
Expand Down Expand Up @@ -64,6 +66,8 @@ const prepareAndUploadFileToS3 = async (
const createAndUploadSampleFile = async (file, experimentId, sampleId, dispatch, selectedTech) => {
const fileType = getFileTypeV2(file.name, selectedTech);

const abortController = new AbortController();

let sampleFileId;

try {
Expand All @@ -73,6 +77,7 @@ const createAndUploadSampleFile = async (file, experimentId, sampleId, dispatch,
sampleId,
fileType,
file,
abortController,
),
);
} catch (e) {
Expand Down Expand Up @@ -114,8 +119,7 @@ const createAndUploadSampleFile = async (file, experimentId, sampleId, dispatch,
);

const uploadUrlParams = { signedUrls, uploadId, fileId: sampleFileId };

await prepareAndUploadFileToS3(file, uploadUrlParams, 'sample', updateSampleFileUploadProgress);
await prepareAndUploadFileToS3(file, uploadUrlParams, 'sample', updateSampleFileUploadProgress, abortController);
} catch (e) {
dispatch(updateSampleFileUpload(
experimentId, sampleId, fileType, UploadStatus.UPLOAD_ERROR,
Expand Down

0 comments on commit 8f11feb

Please sign in to comment.