chore: Tag everything currently unused as legacy.

This commit is contained in:
James A. Petts authored and Erik Ziegler committed 2021-02-11 17:29:07 +01:00
1 parent 8392c1f97e
commit 414ebc6850
161 files changed
+128 -14712

No files matched your search

-61
View File
@@ -1,61 +0,0 @@
import OHIF from '@ohif/core';
import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import dicomParser from 'dicom-parser';
import version from './version.js';
import AppContext from './context/AppContext';
export function setConfiguration(appConfig) {
let homepage;
const { process } = window;
if (process && process.env && process.env.PUBLIC_URL) {
homepage = process.env.PUBLIC_URL;
}
window.info = {
version,
homepage,
};
// For debugging
//if (process.env.node_env === 'development') {
window.cornerstone = cornerstone;
window.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
//}
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
OHIF.user.getAccessToken = () => {
// TODO: Get the Redux store from somewhere else
const state = window.store.getState();
if (!state.oidc || !state.oidc.user) {
return;
}
return state.oidc.user.access_token;
};
OHIF.errorHandler.getHTTPErrorHandler = () => {
// const { appConfig = {} } = AppContext;
return appConfig.httpErrorHandler;
};
cornerstoneWADOImageLoader.configure({
beforeSend: function(xhr) {
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
if (headers.Authorization) {
xhr.setRequestHeader('Authorization', headers.Authorization);
}
},
errorInterceptor: error => {
// const { appConfig = {} } = AppContext;
if (typeof appConfig.httpErrorHandler === 'function') {
appConfig.httpErrorHandler(error);
}
},
});
}
@@ -1,65 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import api from './api/GoogleCloudApi';
import DatasetsList from './DatasetsList';
import './googleCloud.css';
export default class DatasetPicker extends Component {
state = {
error: null,
loading: true,
datasets: [],
filterStr: '',
};
static propTypes = {
project: PropTypes.object,
location: PropTypes.object,
onSelect: PropTypes.func,
accessToken: PropTypes.string,
};
async componentDidMount() {
api.setAccessToken(this.props.accessToken);
const response = await api.loadDatasets(
this.props.project.projectId,
this.props.location.locationId
);
if (response.isError) {
this.setState({
error: response.message,
});
return;
}
this.setState({
datasets: response.data.datasets || [],
loading: false,
});
}
render() {
const { datasets, loading, error, filterStr } = this.state;
const { onSelect } = this.props;
return (
<div>
<input
className="form-control gcp-input"
type="text"
value={filterStr}
onChange={e => this.setState({ filterStr: e.target.value })}
/>
<DatasetsList
datasets={datasets}
loading={loading}
error={error}
filter={filterStr}
onSelect={onSelect}
/>
</div>
);
}
}
@@ -1,155 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import DicomStorePicker from './DicomStorePicker';
import DatasetPicker from './DatasetPicker';
import ProjectPicker from './ProjectPicker';
import LocationPicker from './LocationPicker';
import GoogleCloudApi from './api/GoogleCloudApi';
import './googleCloud.css';
class DatasetSelector extends Component {
state = {
project: null,
location: null,
dataset: null,
unloading: false,
};
static propTypes = {
id: PropTypes.string,
event: PropTypes.string,
user: PropTypes.object,
canClose: PropTypes.string,
setServers: PropTypes.func.isRequired,
};
onProjectSelect = project => {
this.setState({
project,
});
};
onLocationSelect = location => {
this.setState({
location,
});
};
onDatasetSelect = dataset => {
this.setState({
dataset,
});
};
onProjectClick = () => {
this.setState({
dataset: null,
location: null,
project: null,
});
};
onLocationClick = () => {
this.setState({
dataset: null,
location: null,
});
};
onDatasetClick = () => {
this.setState({
dataset: null,
});
};
onDicomStoreSelect = dicomStoreJson => {
const dicomStore = dicomStoreJson.name;
const parts = dicomStore.split('/');
const result = {
wadoUriRoot: GoogleCloudApi.urlBase + `/${dicomStore}/dicomWeb`,
qidoRoot: GoogleCloudApi.urlBase + `/${dicomStore}/dicomWeb`,
wadoRoot: GoogleCloudApi.urlBase + `/${dicomStore}/dicomWeb`,
project: parts[1],
location: parts[3],
dataset: parts[5],
dicomStore: parts[7],
};
this.props.setServers(result);
};
render() {
const accessToken = this.props.user.access_token;
const { project, location, dataset } = this.state;
const {
onProjectClick,
onLocationClick,
onDatasetClick,
onProjectSelect,
onLocationSelect,
onDatasetSelect,
onDicomStoreSelect,
} = this;
let projectBreadcrumbs = (
<div className="gcp-picker--path">
<span>{this.props.t('Select a Project')}</span>
</div>
);
if (project) {
projectBreadcrumbs = (
<div className="gcp-picker--path">
<span onClick={onProjectClick}>{project.name}</span>
{project && location && (
<span onClick={onLocationClick}>
{' '}
-> {location.name.split('/')[3]}
</span>
)}
{project && location && dataset && (
<span onClick={onDatasetClick}>
{' '}
-> {dataset.name.split('/')[5]}
</span>
)}
</div>
);
}
return (
<>
{projectBreadcrumbs}
{!project && (
<ProjectPicker accessToken={accessToken} onSelect={onProjectSelect} />
)}
{project && !location && (
<LocationPicker
accessToken={accessToken}
project={project}
onSelect={onLocationSelect}
/>
)}
{project && location && !dataset && (
<DatasetPicker
accessToken={accessToken}
project={project}
location={location}
onSelect={onDatasetSelect}
/>
)}
{project && location && dataset && (
<DicomStorePicker
accessToken={accessToken}
dataset={dataset}
onSelect={onDicomStoreSelect}
/>
)}
</>
);
}
}
export default withTranslation('Common')(DatasetSelector);
@@ -1,63 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import api from './api/GoogleCloudApi';
import DicomStoreList from './DicomStoreList';
import './googleCloud.css';
export default class DicomStorePicker extends Component {
state = {
error: null,
loading: true,
stores: [],
locations: [],
filterStr: '',
};
static propTypes = {
dataset: PropTypes.object,
onSelect: PropTypes.func,
accessToken: PropTypes.string.isRequired,
};
async componentDidMount() {
api.setAccessToken(this.props.accessToken);
const response = await api.loadDicomStores(this.props.dataset.name);
if (response.isError) {
this.setState({
error: response.message,
});
return;
}
this.setState({
stores: response.data.dicomStores || [],
loading: false,
});
}
render() {
const { stores, loading, error, filterStr } = this.state;
const { onSelect } = this.props;
return (
<div>
<input
className="form-control gcp-input"
type="text"
value={filterStr}
onChange={e => this.setState({ filterStr: e.target.value })}
/>
<DicomStoreList
stores={stores}
loading={loading}
error={error}
filter={filterStr}
onSelect={onSelect}
/>
</div>
);
}
}
@@ -1,56 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import DatasetSelector from './DatasetSelector';
import './googleCloud.css';
import { withTranslation } from 'react-i18next';
import * as GoogleCloudUtilServers from './utils/getServers';
import { servicesManager } from './../App.jsx';
function DicomStorePickerModal({
isOpen = false,
setServers,
onClose,
user,
url,
t,
}) {
const { UIModalService } = servicesManager.services;
const showDicomStorePickerModal = () => {
const handleEvent = data => {
const servers = GoogleCloudUtilServers.getServers(data, data.dicomstore);
setServers(servers);
// Force auto close
UIModalService.hide();
onClose();
};
if (UIModalService) {
UIModalService.show({
content: DatasetSelector,
title: t('Google Cloud Healthcare API'),
contentProps: {
setServers: handleEvent,
user,
url,
},
});
}
};
return (
<React.Fragment>{isOpen && showDicomStorePickerModal()}</React.Fragment>
);
}
DicomStorePickerModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
setServers: PropTypes.func.isRequired,
onClose: PropTypes.func,
user: PropTypes.object.isRequired,
url: PropTypes.string,
};
export default withTranslation('Common')(DicomStorePickerModal);
@@ -1,61 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import api from './api/GoogleCloudApi';
import LocationsList from './LocationsList';
import './googleCloud.css';
export default class LocationPicker extends Component {
state = {
error: null,
loading: true,
locations: [],
filterStr: '',
};
static propTypes = {
project: PropTypes.object,
onSelect: PropTypes.func,
accessToken: PropTypes.string,
};
async componentDidMount() {
api.setAccessToken(this.props.accessToken);
const response = await api.loadLocations(this.props.project.projectId);
if (response.isError) {
this.setState({
error: response.message,
});
return;
}
this.setState({
locations: response.data.locations || [],
loading: false,
});
}
render() {
const { locations, loading, error, filterStr } = this.state;
const { onSelect } = this.props;
return (
<div>
<input
className="form-control gcp-input"
type="text"
value={filterStr}
onChange={e => this.setState({ filterStr: e.target.value })}
/>
<LocationsList
locations={locations}
loading={loading}
error={error}
filter={filterStr}
onSelect={onSelect}
/>
</div>
);
}
}
@@ -1,59 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import api from './api/GoogleCloudApi';
import ProjectsList from './ProjectsList';
import './googleCloud.css';
export default class ProjectPicker extends Component {
state = {
error: null,
loading: true,
projects: [],
};
static propTypes = {
onSelect: PropTypes.func,
accessToken: PropTypes.string,
};
async componentDidMount() {
api.setAccessToken(this.props.accessToken);
const response = await api.loadProjects();
if (response.isError) {
this.setState({
error: response.message,
});
return;
}
this.setState({
projects: response.data.projects || [],
filterStr: '',
loading: false,
});
}
render() {
const { projects, loading, filterStr, error } = this.state;
const { onSelect } = this.props;
return (
<div>
<input
className="form-control gcp-input"
type="text"
value={filterStr}
onChange={e => this.setState({ filterStr: e.target.value })}
/>
<ProjectsList
projects={projects}
loading={loading}
filter={filterStr}
error={error}
onSelect={onSelect}
/>
</div>
);
}
}
@@ -1,89 +0,0 @@
import { httpErrorToStr, checkDicomFile } from '../utils/helpers';
import { api } from 'dicomweb-client';
import { errorHandler } from '@ohif/core';
class DicomUploadService {
async smartUpload(files, url, uploadCallback, cancellationToken) {
const CHUNK_SIZE = 1; // Only one file per request is supported so far
const MAX_PARALLEL_JOBS = 50; // FIXME: tune MAX_PARALLEL_JOBS number
let filesArray = Array.from(files);
if (filesArray.length === 0) {
throw new Error('No files were provided.');
}
let parallelJobsCount = Math.min(filesArray.length, MAX_PARALLEL_JOBS);
let completed = false;
const processJob = async (resolve, reject) => {
while (filesArray.length > 0) {
if (cancellationToken.get()) return;
let chunk = filesArray.slice(0, CHUNK_SIZE);
filesArray = filesArray.slice(CHUNK_SIZE);
let error = null;
try {
if (chunk.length > 1) throw new Error('Not implemented');
if (chunk.length === 1) await this.simpleUpload(chunk[0], url);
} catch (err) {
// It looks like a stupid bug of Babel that err is not an actual Exception object
error = httpErrorToStr(err);
}
chunk.forEach(file => uploadCallback(file.fileId, error));
if (!completed && filesArray.length === 0) {
completed = true;
resolve();
return;
}
}
};
await new Promise(resolve => {
for (let i = 0; i < parallelJobsCount; i++) {
processJob(resolve);
}
});
}
async simpleUpload(file, url) {
const client = this.getClient(url);
const loadedFile = await this.readFile(file);
const content = loadedFile.content;
if (!checkDicomFile(content))
throw new Error('This is not a valid DICOM file.');
await client.storeInstances({ datasets: [content] });
}
readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve({
name: file.name,
size: file.size,
type: file.type,
content: reader.result,
});
};
reader.onerror = error => reject(error);
reader.readAsArrayBuffer(file);
});
}
setRetrieveAuthHeaderFunction(func) {
this.retrieveAuthHeaderFunc = func;
}
getClient(url) {
const headers = this.retrieveAuthHeaderFunc();
const errorInterceptor = errorHandler.getHTTPErrorHandler();
// TODO: a bit weird we are creating a new dicomweb client instance for every upload
return new api.DICOMwebClient({
url,
headers,
});
}
}
export default new DicomUploadService();
@@ -1,99 +0,0 @@
import dcmjs from 'dcmjs';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import FileLoader from './fileLoader';
import OHIF from '@ohif/core';
const metadataProvider = OHIF.cornerstone.metadataProvider;
const DICOMFileLoader = new (class extends FileLoader {
fileType = 'application/dicom';
loadFile(file, imageId) {
return cornerstoneWADOImageLoader.wadouri.loadFileRequest(imageId);
}
getDataset(image, imageId) {
let dataset = {};
try {
const dicomData = dcmjs.data.DicomMessage.readFile(image);
dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
dicomData.dict
);
metadataProvider.addInstance(dataset);
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(
dicomData.meta
);
} catch (e) {
console.error('Error reading dicom file', e);
}
// Set imageId on dataset to be consumed later on
dataset.imageId = imageId;
return dataset;
}
getStudies(dataset, imageId) {
return this.getStudyFromDataset(dataset);
}
getStudyFromDataset(dataset = {}) {
const {
StudyInstanceUID,
StudyDate,
StudyTime,
AccessionNumber,
ReferringPhysicianName,
PatientName,
PatientID,
PatientBirthDate,
PatientSex,
StudyID,
StudyDescription,
SeriesInstanceUID,
SeriesDescription,
SeriesNumber,
imageId,
} = dataset;
const instance = {
metadata: dataset,
url: imageId,
};
const series = {
SeriesInstanceUID: SeriesInstanceUID,
SeriesDescription: SeriesDescription,
SeriesNumber: SeriesNumber,
instances: [instance],
};
const study = {
StudyInstanceUID,
StudyDate,
StudyTime,
AccessionNumber,
ReferringPhysicianName,
PatientName,
PatientID,
PatientBirthDate,
PatientSex,
StudyID,
StudyDescription,
/*
TODO: in case necessary to uncomment this block, double check every property
numberOfStudyRelatedSeries: NumberOfStudyRelatedSeries || DICOMWeb.getString(dataset['00201206']),
numberOfStudyRelatedInstances: NumberOfStudyRelatedInstances || DICOMWeb.getString(dataset['00201208']),
Modality: Modality || DICOMWeb.getString(dataset['00080060']),
ModalitiesInStudy: ModalitiesInStudy || DICOMWeb.getString(dataset['00080061']),
modalities:
*/
series: [series],
};
return study;
}
})();
export default DICOMFileLoader;
@@ -1,82 +0,0 @@
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import FileLoader from './fileLoader';
import PDFFileLoader from './pdfFileLoader';
import DICOMFileLoader from './dicomFileLoader';
class FileLoaderService extends FileLoader {
fileType;
loader;
constructor(file) {
super();
const fileType = file && file.type;
this.loader = this.getLoader(fileType);
this.fileType = this.loader.fileType;
}
static groupSeries(studies) {
const groupBy = (list, groupByKey, listKey) => {
let nonKeyCounter = 1;
return list.reduce((acc, obj) => {
let key = obj[groupByKey];
const list = obj[listKey];
// in case key not found, group it using counter
key = !!key ? key : '' + nonKeyCounter++;
if (!acc[key]) {
acc[key] = { ...obj };
acc[key][listKey] = [];
}
acc[key][listKey].push(...list);
return acc;
}, {});
};
const studiesGrouped = Object.values(
groupBy(studies, 'StudyInstanceUID', 'series')
);
const result = studiesGrouped.map(studyGroup => {
const seriesGrouped = groupBy(
studyGroup.series,
'SeriesInstanceUID',
'instances'
);
studyGroup.series = Object.values(seriesGrouped);
return studyGroup;
});
return result;
}
addFile(file) {
return cornerstoneWADOImageLoader.wadouri.fileManager.add(file);
}
loadFile(file, imageId) {
return this.loader.loadFile(file, imageId);
}
getDataset(image, imageId) {
return this.loader.getDataset(image, imageId);
}
getStudies(dataset, imageId) {
return this.loader.getStudies(dataset, imageId);
}
getLoader(fileType) {
if (fileType === 'application/pdf') {
return PDFFileLoader;
} else {
// Default to dicom loader
return DICOMFileLoader;
}
}
}
export default FileLoaderService;
@@ -1,60 +0,0 @@
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import FileLoader from './fileLoader';
const PDFFileLoader = new (class extends FileLoader {
fileType = 'application/pdf';
loadFile(file, imageId) {
return cornerstoneWADOImageLoader.wadouri.loadFileRequest(imageId);
}
getDataset(image, imageId) {
const dataset = {};
dataset.imageId = image.imageId || imageId;
return dataset;
}
getStudies(dataset, imageId) {
return this.getDefaultStudy(imageId);
}
getDefaultStudy(imageId) {
const study = {
StudyInstanceUID: '',
StudyDate: '',
StudyTime: '',
AccessionNumber: '',
ReferringPhysicianName: '',
PatientName: '',
PatientID: '',
PatientBirthdate: '',
PatientSex: '',
StudyId: '',
StudyDescription: '',
series: [
{
SeriesInstanceUID: '',
SeriesDescription: '',
SeriesNumber: '',
instances: [
{
metadata: {
SOPInstanceUID: '',
SOPClassUID: '1.2.840.10008.5.1.4.1.1.104.1',
Rows: '',
Columns: '',
NumberOfFrames: 0,
InstanceNumber: 1,
},
getImageId: () => imageId,
isLocalFile: true,
},
],
},
],
};
return study;
}
})();
export default PDFFileLoader;
@@ -1,22 +0,0 @@
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
let initialized = false;
export default function initWebWorkers() {
const config = {
maxWebWorkers: Math.max(navigator.hardwareConcurrency - 1, 1),
startWebWorkersOnDemand: true,
taskConfiguration: {
decodeTask: {
initializeCodecsOnStartup: false,
usePDFJS: false,
strict: false,
},
},
};
if (!initialized) {
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
initialized = true;
}
}
@@ -1,23 +0,0 @@
import initWebWorkers from './initWebWorkers.js';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
describe('initWebWorkers', () => {
it("initializes cornerstoneWADOImageLoader's web workers", () => {
initWebWorkers();
expect(
cornerstoneWADOImageLoader.webWorkerManager.initialize
).toHaveBeenCalled();
});
});
describe('initWebWorkers', () => {
it("initializes cornerstoneWADOImageLoader's web workers only once", () => {
initWebWorkers();
initWebWorkers();
expect(
cornerstoneWADOImageLoader.webWorkerManager.initialize
).toHaveBeenCalledTimes(1);
});
});