feat(ViewerLocalFileData): Add drag/drop to load DICOM files in the Viewer at /local (#644)

This commit is contained in:
Erik Ziegler 2019-07-11 13:49:29 +02:00 committed by GitHub
parent f256ac5a7d
commit 2f104b5e91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 410 additions and 47 deletions

View File

@ -101,6 +101,7 @@
"ohif-core": "0.9.1",
"oidc-client": "1.7.x",
"prop-types": "^15.7.2",
"react-dropzone": "^10.1.5",
"react-i18next": "^10.11.0",
"react-redux": "^7.1.0",
"react-resize-detector": "^4.2.0",

View File

@ -9,6 +9,7 @@ import { ViewerbaseDragDropContext } from 'react-viewerbase';
// import asyncComponent from './components/AsyncComponent.js'
import IHEInvokeImageDisplay from './routes/IHEInvokeImageDisplay.js';
import ViewerRouting from './routes/ViewerRouting.js';
import ViewerLocalFileData from './connectedComponents/ViewerLocalFileData.js';
import StudyListRouting from './studylist/StudyListRouting.js';
import StandaloneRouting from './routes/StandaloneRouting.js';
import CallbackPage from './routes/CallbackPage.js';
@ -96,6 +97,10 @@ class OHIFStandaloneViewer extends Component {
* See http://reactcommunity.org/react-transition-group/with-react-router/
*/
const routes = [
{
path: '/local',
Component: ViewerLocalFileData,
},
{
path: '/viewer',
Component: StandaloneRouting,

View File

@ -0,0 +1,15 @@
.drag-drop-instructions {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.drag-drop-instructions h3 {
color: var(--active-color);
}
.drag-drop-instructions h4 {
color: var(--text-secondary-color);
}

View File

@ -0,0 +1,117 @@
import React, { Component } from 'react';
import { metadata, utils } from 'ohif-core';
import ConnectedViewer from './ConnectedViewer.js';
import PropTypes from 'prop-types';
import { extensionManager } from './../App.js';
import Dropzone from 'react-dropzone';
import filesToStudies from '../lib/filesToStudies';
import './ViewerLocalFileData.css';
import { withTranslation } from 'react-i18next';
const { OHIFStudyMetadata } = metadata;
const { studyMetadataManager, updateMetaDataManager } = utils;
class ViewerLocalFileData extends Component {
static propTypes = {
studies: PropTypes.array,
};
state = {
studies: null,
loading: false,
error: null,
};
updateStudies = studies => {
// Render the viewer when the data is ready
studyMetadataManager.purge();
// Map studies to new format, update metadata manager?
const updatedStudies = studies.map(study => {
const studyMetadata = new OHIFStudyMetadata(
study,
study.studyInstanceUid
);
const sopClassHandlerModules =
extensionManager.modules['sopClassHandlerModule'];
study.displaySets =
study.displaySets ||
studyMetadata.createDisplaySets(sopClassHandlerModules);
studyMetadata.setDisplaySets(study.displaySets);
// Updates WADO-RS metaDataManager
updateMetaDataManager(study);
studyMetadataManager.add(studyMetadata);
return study;
});
this.setState({
studies: updatedStudies,
});
};
render() {
const onDrop = async acceptedFiles => {
this.setState({ loading: true });
const studies = await filesToStudies(acceptedFiles);
const updatedStudies = this.updateStudies(studies);
if (!updatedStudies) {
return;
}
this.setState({ studies: updatedStudies, loading: false });
};
if (this.state.error) {
return <div>Error: {JSON.stringify(this.state.error)}</div>;
}
return (
<Dropzone onDrop={onDrop}>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()} style={{ width: '100%', height: '100%' }}>
{this.state.studies ? (
<ConnectedViewer
studies={this.state.studies}
studyInstanceUids={
this.state.studies &&
this.state.studies.map(a => a.studyInstanceUid)
}
/>
) : (
<div className={'drag-drop-instructions'}>
<div className={'drag-drop-contents'}>
{this.state.loading ? (
<h3>{this.props.t('Loading...')}</h3>
) : (
<>
<h3>
{this.props.t(
'Drag and Drop DICOM files here to load them in the Viewer'
)}
</h3>
<h4>
{this.props.t(
"Or click to load the browser's file selector"
)}
</h4>
</>
)}
</div>
<input {...getInputProps()} style={{ display: 'none' }} />
</div>
)}
</div>
)}
</Dropzone>
);
}
}
export default withTranslation('Common')(ViewerLocalFileData);

152
src/lib/filesToStudies.js Normal file
View File

@ -0,0 +1,152 @@
import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import * as dcmjs from 'dcmjs';
function datasetsToStudies(datasets) {
const StudyInstanceUIDs = new Set();
datasets.forEach(ds => {
StudyInstanceUIDs.add(ds.StudyInstanceUID);
});
const studies = [];
Array.from(StudyInstanceUIDs).forEach(studyInstanceUid => {
const studyDatasets = datasets.filter(
ds => ds.StudyInstanceUID === studyInstanceUid
);
const firstDataset = studyDatasets[0];
const study = {
studyInstanceUid: firstDataset.StudyInstanceUID,
studyDate: firstDataset.StudyDate,
studyTime: firstDataset.StudyTime,
accessionNumber: firstDataset.AccessionNumber,
referringPhysicianName: firstDataset.ReferringPhysicianName,
patientName: firstDataset.PatientName,
patientId: firstDataset.PatientID,
patientBirthdate: firstDataset.PatientBirthDate,
patientSex: firstDataset.PatientSex,
studyId: firstDataset.StudyID,
studyDescription: firstDataset.StudyDescription,
//numberOfStudyRelatedSeries: DICOMWeb.getString(study['00201206']),
//numberOfStudyRelatedInstances: DICOMWeb.getString(study['00201208']),
// modality: DICOMWeb.getString(study['00080060']),
// modalitiesInStudy: DICOMWeb.getString(study['00080061']),
//modalities:
seriesList: [],
};
const SeriesInstanceUIDs = new Set();
studyDatasets.forEach(ds => {
SeriesInstanceUIDs.add(ds.SeriesInstanceUID);
});
Array.from(SeriesInstanceUIDs).forEach(seriesInstanceUid => {
const seriesDatasets = studyDatasets.filter(
ds => ds.SeriesInstanceUID === seriesInstanceUid
);
const SOPInstanceUIDs = new Set();
seriesDatasets.forEach(ds => {
SOPInstanceUIDs.add(ds.SOPInstanceUID);
study.seriesList.push({
seriesInstanceUid: ds.SeriesInstanceUID,
seriesDescription: ds.SeriesDescription,
seriesNumber: ds.SeriesNumber,
instances: [],
});
});
Array.from(SOPInstanceUIDs).forEach(sopInstanceUid => {
const instance = seriesDatasets.find(
a => a.SOPInstanceUID === sopInstanceUid
);
const series = study.seriesList.find(
a => a.seriesInstanceUid === seriesInstanceUid
);
series.instances.push({
sopInstanceUid: instance.SOPInstanceUID,
sopClassUid: instance.SOPClassUID,
rows: instance.Rows,
columns: instance.Columns,
numberOfFrames: instance.NumberOfFrames,
instanceNumber: instance.InstanceNumber,
getImageId: () => instance.imageId, // TODO: Change getImageId to check for instance.imageId property first.
/*imageType: DICOMWeb.getString(instance['00080008']),
modality: DICOMWeb.getString(instance['00080060']),
instanceNumber: DICOMWeb.getNumber(instance['00200013']),
imagePositionPatient: DICOMWeb.getString(instance['00200032']),
imageOrientationPatient: DICOMWeb.getString(instance['00200037']),
frameOfReferenceUID: DICOMWeb.getString(instance['00200052']),
sliceLocation: DICOMWeb.getNumber(instance['00201041']),
samplesPerPixel: DICOMWeb.getNumber(instance['00280002']),
photometricInterpretation: DICOMWeb.getString(instance['00280004']),
planarConfiguration: DICOMWeb.getNumber(instance['00280006']),
pixelSpacing: DICOMWeb.getString(instance['00280030']),
pixelAspectRatio: DICOMWeb.getString(instance['00280034']),
bitsAllocated: DICOMWeb.getNumber(instance['00280100']),
bitsStored: DICOMWeb.getNumber(instance['00280101']),
highBit: DICOMWeb.getNumber(instance['00280102']),
pixelRepresentation: DICOMWeb.getNumber(instance['00280103']),
smallestPixelValue: DICOMWeb.getNumber(instance['00280106']),
largestPixelValue: DICOMWeb.getNumber(instance['00280107']),
windowCenter: DICOMWeb.getString(instance['00281050']),
windowWidth: DICOMWeb.getString(instance['00281051']),
rescaleIntercept: DICOMWeb.getNumber(instance['00281052']),
rescaleSlope: DICOMWeb.getNumber(instance['00281053']),
rescaleType: DICOMWeb.getNumber(instance['00281054']),
sourceImageInstanceUid: getSourceImageInstanceUid(instance),
laterality: DICOMWeb.getString(instance['00200062']),
viewPosition: DICOMWeb.getString(instance['00185101']),
acquisitionDateTime: DICOMWeb.getString(instance['0008002A']),
frameIncrementPointer: getFrameIncrementPointer(instance['00280009']),
frameTime: DICOMWeb.getNumber(instance['00181063']),
frameTimeVector: parseFloatArray(
DICOMWeb.getString(instance['00181065'])
),
sliceThickness: DICOMWeb.getNumber(instance['00180050']),
spacingBetweenSlices: DICOMWeb.getString(instance['00180088']),
lossyImageCompression: DICOMWeb.getString(instance['00282110']),
derivationDescription: DICOMWeb.getString(instance['00282111']),
lossyImageCompressionRatio: DICOMWeb.getString(instance['00282112']),
lossyImageCompressionMethod: DICOMWeb.getString(instance['00282114']),
echoNumber: DICOMWeb.getString(instance['00180086']),
contrastBolusAgent: DICOMWeb.getString(instance['00180010']),
radiopharmaceuticalInfo: getRadiopharmaceuticalInfo(instance),
wadouri: WADOProxy.convertURL(wadouri, server),
wadorsuri: WADOProxy.convertURL(wadorsuri, server),*/
});
});
});
studies.push(study);
});
console.warn(studies);
return studies;
}
export default async function filesToStudies(files) {
const imagePromises = files.map(file => {
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(file);
return cornerstone.loadAndCacheImage(imageId);
});
const images = await Promise.all(imagePromises);
const datasets = images.map(image => {
const arrayBuffer = image.data.byteArray.buffer;
const dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
dicomData.dict
);
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(
dicomData.meta
);
dataset.imageId = image.imageId;
return dataset;
});
return datasetsToStudies(datasets);
}

View File

@ -1,5 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Dropzone from 'react-dropzone';
import OHIF from 'ohif-core';
import { withRouter } from 'react-router-dom';
import { withTranslation } from 'react-i18next';
@ -8,6 +9,7 @@ import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
import moment from 'moment';
import ConnectedDicomFilesUploader from '../googleCloud/ConnectedDicomFilesUploader';
import ConnectedDicomStorePicker from '../googleCloud/ConnectedDicomStorePicker';
import filesToStudies from '../lib/filesToStudies.js';
class StudyListWithData extends Component {
state = {
@ -171,6 +173,19 @@ class StudyListWithData extends Component {
};
render() {
const onDrop = async acceptedFiles => {
// Do something with the files
console.warn(acceptedFiles);
try {
const studies = await filesToStudies(acceptedFiles);
this.setState({ studies });
} catch (error) {
this.setState({ error });
}
};
if (this.state.error) {
return <div>Error: {JSON.stringify(this.state.error)}</div>;
} else if (this.state.studies === null && !this.state.modalComponentId) {
@ -216,24 +231,44 @@ class StudyListWithData extends Component {
);
}
console.warn(this.state.studies);
const studyList = (
<div className="paginationArea">
<StudyList
studies={this.state.studies}
studyListFunctionsEnabled={false}
onImport={this.onImport}
onSelectItem={this.onSelectItem}
pageSize={this.rowsPerPage}
defaultSort={StudyListWithData.defaultSort}
studyListDateFilterNumDays={
StudyListWithData.studyListDateFilterNumDays
}
onSearch={this.onSearch}
>
{healthCareApiButtons}
{healthCareApiWindows}
</StudyList>
</div>
<Dropzone onDrop={onDrop}>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()} className="paginationArea">
{this.state.studies ? (
<StudyList
studies={this.state.studies}
studyListFunctionsEnabled={false}
onImport={this.onImport}
onSelectItem={this.onSelectItem}
pageSize={this.rowsPerPage}
defaultSort={StudyListWithData.defaultSort}
studyListDateFilterNumDays={
StudyListWithData.studyListDateFilterNumDays
}
onSearch={this.onSearch}
>
{healthCareApiButtons}
{healthCareApiWindows}
</StudyList>
) : (
<div className={'drag-drop-instructions'}>
<h3>
{this.props.t(
'Drag and Drop DICOM files here to load them in the Viewer'
)}
</h3>
<h4>
{this.props.t("Or click to load the browser's file selector")}
</h4>
<input {...getInputProps()} style={{ display: 'none' }} />
</div>
)}
</div>
)}
</Dropzone>
);
return (
<>

View File

@ -894,7 +894,7 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.4":
version "7.5.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b"
integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q==
@ -1518,11 +1518,11 @@
loader-utils "^1.1.0"
"@tanem/react-nprogress@^1.1.25":
version "1.1.30"
resolved "https://registry.yarnpkg.com/@tanem/react-nprogress/-/react-nprogress-1.1.30.tgz#fd10c20f2c98c3f8f78df4c1ba842105f2b09021"
integrity sha512-OGN0WNNTGvA7kAUSU1Ajn0BBCDVxZoU1xGTZSQgjwqDeeRChXyidt8cuB85yvFxhCrzyVf8ovM3e5uDX43ROaQ==
version "1.1.31"
resolved "https://registry.yarnpkg.com/@tanem/react-nprogress/-/react-nprogress-1.1.31.tgz#967bbf0182a1af562f4667fea0c0ee31ea34e078"
integrity sha512-v2C4+E9/Od2iGsrEWdbBBLTEYl7TvRos+I7XfnF2W1421F1MoUH0hsDrU7leqoEKQhrimlKDU54hwV09egKhgw==
dependencies:
"@babel/runtime" "^7.4.5"
"@babel/runtime" "^7.5.4"
hoist-non-react-statics "^3.3.0"
prop-types "^15.7.2"
@ -2387,6 +2387,13 @@ atob@^2.1.1:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
attr-accept@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.3.tgz#48230c79f93790ef2775fcec4f0db0f5db41ca52"
integrity sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==
dependencies:
core-js "^2.5.0"
autoprefixer@^9.4.9, autoprefixer@^9.5.1:
version "9.6.1"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47"
@ -3797,7 +3804,7 @@ core-js@^1.0.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
core-js@^2.4.0, core-js@^2.5.7, core-js@^2.6.5:
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7, core-js@^2.6.5:
version "2.6.9"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
@ -4815,9 +4822,9 @@ ee-first@1.1.1:
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.150:
version "1.3.188"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.188.tgz#e28e1afe4bb229989e280bfd3b395c7ec03c8b7a"
integrity sha512-tEQcughYIMj8WDMc59EGEtNxdGgwal/oLLTDw+NEqJRJwGflQvH3aiyiexrWeZOETP4/ko78PVr6gwNhdozvuQ==
version "1.3.189"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.189.tgz#aa84055eb36d364a68852ad2d25e1315a1d06196"
integrity sha512-C26Kv6/rLNmGDaPR5HORMtTQat9aWBBKjQk9aFtN1Bk6cQBSw8cYdsel/mcrQlNlMMjt1sAKsTYqf77+sK2uTw==
elegant-spinner@^1.0.1:
version "1.0.1"
@ -5656,6 +5663,13 @@ file-loader@3.0.1:
loader-utils "^1.0.2"
schema-utils "^1.0.0"
file-selector@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.12.tgz#fe726547be219a787a9dcc640575a04a032b1fd0"
integrity sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ==
dependencies:
tslib "^1.9.0"
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@ -7148,9 +7162,9 @@ inquirer@6.2.2:
through "^2.3.6"
inquirer@^6.2.2:
version "6.4.1"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.4.1.tgz#7bd9e5ab0567cd23b41b0180b68e0cfa82fc3c0b"
integrity sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==
version "6.5.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42"
integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==
dependencies:
ansi-escapes "^3.2.0"
chalk "^2.4.2"
@ -7158,7 +7172,7 @@ inquirer@^6.2.2:
cli-width "^2.0.0"
external-editor "^3.0.3"
figures "^2.0.0"
lodash "^4.17.11"
lodash "^4.17.12"
mute-stream "0.0.7"
run-async "^2.2.0"
rxjs "^6.4.0"
@ -8771,6 +8785,11 @@ lie@~3.1.0:
dependencies:
immediate "~3.0.5"
lines-and-columns@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
lint-staged@^8.2.1:
version "8.2.1"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.2.1.tgz#752fcf222d9d28f323a3b80f1e668f3654ff221f"
@ -9156,7 +9175,7 @@ lodash@4.17.11:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
"lodash@>=3.5 <5", lodash@^4.1.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1:
"lodash@>=3.5 <5", lodash@^4.1.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1:
version "4.17.14"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
@ -10898,6 +10917,16 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
parse-json@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f"
integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
lines-and-columns "^1.1.6"
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
@ -12468,6 +12497,15 @@ react-dom@^16.7.0:
prop-types "^15.6.2"
scheduler "^0.13.6"
react-dropzone@^10.1.5:
version "10.1.5"
resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-10.1.5.tgz#5f2817ab924b270010c7034fe01f49b6240b9c91"
integrity sha512-Hbe7soBc/i1fid7K3BU8T1oUJFnYO2AicS22F2MxcueMYDfKBWqZMr5ED3CoTAMs//9t2W30eyFiXm1h4wLCqA==
dependencies:
attr-accept "^1.1.3"
file-selector "^0.1.11"
prop-types "^15.7.2"
react-error-overlay@^5.1.6:
version "5.1.6"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.6.tgz#0cd73407c5d141f9638ae1e0c63e7b2bf7e9929d"
@ -12824,14 +12862,14 @@ read-pkg@^3.0.0:
path-type "^3.0.0"
read-pkg@^5.0.0, read-pkg@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.1.1.tgz#5cf234dde7a405c90c88a519ab73c467e9cb83f5"
integrity sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w==
version "5.2.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
dependencies:
"@types/normalize-package-data" "^2.4.0"
normalize-package-data "^2.5.0"
parse-json "^4.0.0"
type-fest "^0.4.1"
parse-json "^5.0.0"
type-fest "^0.6.0"
read@1, read@~1.0.1, read@~1.0.7:
version "1.0.7"
@ -12969,9 +13007,9 @@ redux-thunk@^2.3.0:
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
redux@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.3.tgz#0ca18be085e6cf6ed50e445a125f85e8b26b266b"
integrity sha512-v/Iaw67Pe+na+cZvcKvPxAKT1ww5kM+M09fmaCndCQC4Lo434AYb5975HJgJlp0D7dJxfYaLxMD4VwfpLOZ1Rw==
version "4.0.4"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==
dependencies:
loose-envify "^1.4.0"
symbol-observable "^1.2.0"
@ -14165,9 +14203,9 @@ spdx-expression-parse@^3.0.0:
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
version "3.0.5"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
spdy-transport@^3.0.0:
version "3.0.0"
@ -15098,16 +15136,16 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
type-fest@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8"
integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==
type-fest@^0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2"
integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==
type-fest@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"