diff --git a/package.json b/package.json index e156e1c04..317ebc67d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/OHIFStandaloneViewer.js b/src/OHIFStandaloneViewer.js index d933a5de3..c5f8bc716 100644 --- a/src/OHIFStandaloneViewer.js +++ b/src/OHIFStandaloneViewer.js @@ -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, diff --git a/src/connectedComponents/ViewerLocalFileData.css b/src/connectedComponents/ViewerLocalFileData.css new file mode 100644 index 000000000..2e6f396fc --- /dev/null +++ b/src/connectedComponents/ViewerLocalFileData.css @@ -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); +} diff --git a/src/connectedComponents/ViewerLocalFileData.js b/src/connectedComponents/ViewerLocalFileData.js new file mode 100644 index 000000000..eb49fc2ea --- /dev/null +++ b/src/connectedComponents/ViewerLocalFileData.js @@ -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
Error: {JSON.stringify(this.state.error)}
; + } + + return ( + + {({ getRootProps, getInputProps }) => ( +
+ {this.state.studies ? ( + a.studyInstanceUid) + } + /> + ) : ( +
+
+ {this.state.loading ? ( +

{this.props.t('Loading...')}

+ ) : ( + <> +

+ {this.props.t( + 'Drag and Drop DICOM files here to load them in the Viewer' + )} +

+

+ {this.props.t( + "Or click to load the browser's file selector" + )} +

+ + )} +
+ +
+ )} +
+ )} +
+ ); + } +} + +export default withTranslation('Common')(ViewerLocalFileData); diff --git a/src/lib/filesToStudies.js b/src/lib/filesToStudies.js new file mode 100644 index 000000000..03d227843 --- /dev/null +++ b/src/lib/filesToStudies.js @@ -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); +} diff --git a/src/studylist/StudyListWithData.js b/src/studylist/StudyListWithData.js index 3f97015cf..d855eb71d 100644 --- a/src/studylist/StudyListWithData.js +++ b/src/studylist/StudyListWithData.js @@ -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
Error: {JSON.stringify(this.state.error)}
; } else if (this.state.studies === null && !this.state.modalComponentId) { @@ -216,24 +231,44 @@ class StudyListWithData extends Component { ); } + console.warn(this.state.studies); + const studyList = ( -
- - {healthCareApiButtons} - {healthCareApiWindows} - -
+ + {({ getRootProps, getInputProps }) => ( +
+ {this.state.studies ? ( + + {healthCareApiButtons} + {healthCareApiWindows} + + ) : ( +
+

+ {this.props.t( + 'Drag and Drop DICOM files here to load them in the Viewer' + )} +

+

+ {this.props.t("Or click to load the browser's file selector")} +

+ +
+ )} +
+ )} +
); return ( <> diff --git a/yarn.lock b/yarn.lock index 5bd22c4f2..d5a95fc2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"