refactor(GoogleCloud): Clean up some of the Healthcare API Adapter components (#641)
This commit is contained in:
parent
4a09f33446
commit
091cab49e0
@ -1,5 +1,5 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import DicomFileUploader from './DicomFileUploader.js';
|
import DicomFileUploaderModal from './DicomFileUploaderModal.js';
|
||||||
|
|
||||||
const isActive = a => a.active === true;
|
const isActive = a => a.active === true;
|
||||||
|
|
||||||
@ -17,6 +17,6 @@ const mapStateToProps = state => {
|
|||||||
const ConnectedDicomFileUploader = connect(
|
const ConnectedDicomFileUploader = connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
null
|
null
|
||||||
)(DicomFileUploader);
|
)(DicomFileUploaderModal);
|
||||||
|
|
||||||
export default ConnectedDicomFileUploader;
|
export default ConnectedDicomFileUploader;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import DicomStorePickerWindow from './DicomStorePickerWindow.js';
|
import DicomStorePickerModal from './DicomStorePickerModal.js';
|
||||||
|
|
||||||
const isActive = a => a.active === true;
|
const isActive = a => a.active === true;
|
||||||
|
|
||||||
@ -29,6 +29,6 @@ const mapDispatchToProps = dispatch => {
|
|||||||
const ConnectedDicomStorePicker = connect(
|
const ConnectedDicomStorePicker = connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(DicomStorePickerWindow);
|
)(DicomStorePickerModal);
|
||||||
|
|
||||||
export default ConnectedDicomStorePicker;
|
export default ConnectedDicomStorePicker;
|
||||||
|
|||||||
@ -5,14 +5,11 @@ import DatasetsList from './DatasetsList';
|
|||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
|
||||||
export default class DatasetPicker extends Component {
|
export default class DatasetPicker extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
error: null,
|
error: null,
|
||||||
loading: false,
|
loading: true,
|
||||||
datasets: [],
|
datasets: [],
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
project: PropTypes.object,
|
project: PropTypes.object,
|
||||||
@ -20,7 +17,6 @@ export default class DatasetPicker extends Component {
|
|||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
oidcKey: PropTypes.string,
|
oidcKey: PropTypes.string,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
api.setOidcStorageKey(this.props.oidcKey);
|
api.setOidcStorageKey(this.props.oidcKey);
|
||||||
@ -29,12 +25,19 @@ export default class DatasetPicker extends Component {
|
|||||||
this.props.project.projectId,
|
this.props.project.projectId,
|
||||||
this.props.location.locationId
|
this.props.location.locationId
|
||||||
);
|
);
|
||||||
this.loading = false;
|
|
||||||
if (response.isError) {
|
if (response.isError) {
|
||||||
this.error = response.message;
|
this.setState({
|
||||||
|
error: response.message,
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ datasets: response.data.datasets || [] });
|
|
||||||
|
this.setState({
|
||||||
|
datasets: response.data.datasets || [],
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -46,7 +49,7 @@ export default class DatasetPicker extends Component {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
></DatasetsList>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
import DicomStorePicker from './DicomStorePicker';
|
import DicomStorePicker from './DicomStorePicker';
|
||||||
import DatasetPicker from './DatasetPicker';
|
import DatasetPicker from './DatasetPicker';
|
||||||
import ProjectPicker from './ProjectPicker';
|
import ProjectPicker from './ProjectPicker';
|
||||||
@ -7,16 +8,13 @@ import LocationPicker from './LocationPicker';
|
|||||||
import GoogleCloudApi from './api/GoogleCloudApi';
|
import GoogleCloudApi from './api/GoogleCloudApi';
|
||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
|
||||||
export default class DatasetSelector extends Component {
|
class DatasetSelector extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
project: null,
|
project: null,
|
||||||
location: null,
|
location: null,
|
||||||
dataset: null,
|
dataset: null,
|
||||||
unloading: false,
|
unloading: false,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
@ -25,23 +23,22 @@ export default class DatasetSelector extends Component {
|
|||||||
canClose: PropTypes.string,
|
canClose: PropTypes.string,
|
||||||
setServers: PropTypes.func.isRequired,
|
setServers: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
onProjectSelect = project => {
|
onProjectSelect = project => {
|
||||||
this.setState({
|
this.setState({
|
||||||
project: project,
|
project,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onLocationSelect = location => {
|
onLocationSelect = location => {
|
||||||
this.setState({
|
this.setState({
|
||||||
location: location,
|
location,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onDatasetSelect = dataset => {
|
onDatasetSelect = dataset => {
|
||||||
this.setState({
|
this.setState({
|
||||||
dataset: dataset,
|
dataset,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,65 +89,68 @@ export default class DatasetSelector extends Component {
|
|||||||
onDatasetSelect,
|
onDatasetSelect,
|
||||||
onDicomStoreSelect,
|
onDicomStoreSelect,
|
||||||
} = this;
|
} = this;
|
||||||
return (
|
|
||||||
<>
|
let projectBreadcrumbs = (
|
||||||
<span className="gcp-picker--title">Google Cloud Healthcare API</span>
|
<div className="gcp-picker--path">
|
||||||
{project && (
|
<span>{this.props.t('Select a Project')}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (project) {
|
||||||
|
projectBreadcrumbs = (
|
||||||
<div className="gcp-picker--path">
|
<div className="gcp-picker--path">
|
||||||
<span onClick={onProjectClick}>{project.name}</span>
|
<span onClick={onProjectClick}>{project.name}</span>
|
||||||
{project && location && (
|
{project && location && (
|
||||||
<>
|
|
||||||
<span onClick={onLocationClick}>
|
<span onClick={onLocationClick}>
|
||||||
{' '}
|
{' '}
|
||||||
-> {location.name.split('/')[3]}
|
-> {location.name.split('/')[3]}
|
||||||
</span>
|
</span>
|
||||||
|
)}
|
||||||
{project && location && dataset && (
|
{project && location && dataset && (
|
||||||
<span onClick={onDatasetClick}>
|
<span onClick={onDatasetClick}>
|
||||||
{' '}
|
{' '}
|
||||||
-> {dataset.name.split('/')[5]}
|
-> {dataset.name.split('/')[5]}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{projectBreadcrumbs}
|
||||||
{!project && (
|
{!project && (
|
||||||
<ProjectPicker
|
<ProjectPicker
|
||||||
oidcKey={this.props.oidcKey}
|
oidcKey={this.props.oidcKey}
|
||||||
onSelect={onProjectSelect}
|
onSelect={onProjectSelect}
|
||||||
></ProjectPicker>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{project && !location && (
|
{project && !location && (
|
||||||
<>
|
|
||||||
<LocationPicker
|
<LocationPicker
|
||||||
oidcKey={this.props.oidcKey}
|
oidcKey={this.props.oidcKey}
|
||||||
project={project}
|
project={project}
|
||||||
onSelect={onLocationSelect}
|
onSelect={onLocationSelect}
|
||||||
></LocationPicker>
|
/>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{project && location && !dataset && (
|
{project && location && !dataset && (
|
||||||
<>
|
|
||||||
<DatasetPicker
|
<DatasetPicker
|
||||||
oidcKey={this.props.oidcKey}
|
oidcKey={this.props.oidcKey}
|
||||||
project={project}
|
project={project}
|
||||||
location={location}
|
location={location}
|
||||||
onSelect={onDatasetSelect}
|
onSelect={onDatasetSelect}
|
||||||
></DatasetPicker>
|
/>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{project && location && dataset && (
|
{project && location && dataset && (
|
||||||
<>
|
|
||||||
<DicomStorePicker
|
<DicomStorePicker
|
||||||
oidcKey={this.props.oidcKey}
|
oidcKey={this.props.oidcKey}
|
||||||
dataset={dataset}
|
dataset={dataset}
|
||||||
onSelect={onDicomStoreSelect}
|
onSelect={onDicomStoreSelect}
|
||||||
></DicomStorePicker>
|
/>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(DatasetSelector);
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { Icon } from 'react-viewerbase';
|
||||||
|
|
||||||
export default class DatasetsList extends Component {
|
class DatasetsList extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
search: '',
|
search: '',
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
datasets: PropTypes.array,
|
datasets: PropTypes.array,
|
||||||
@ -16,16 +15,19 @@ export default class DatasetsList extends Component {
|
|||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
renderTableRow(dataset) {
|
static defaultProps = {
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTableRow = dataset => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={dataset.name}
|
key={dataset.name}
|
||||||
className={
|
className={
|
||||||
this.state.highlightedItem === dataset.name
|
this.state.highlightedItem === dataset.name
|
||||||
? 'studylistStudy noselect active'
|
? 'noselect active'
|
||||||
: 'studylistStudy noselect'
|
: 'noselect'
|
||||||
}
|
}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
this.onHighlightItem(dataset.name);
|
this.onHighlightItem(dataset.name);
|
||||||
@ -37,21 +39,42 @@ export default class DatasetsList extends Component {
|
|||||||
<td>{dataset.name.split('/')[5]}</td>
|
<td>{dataset.name.split('/')[5]}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
onHighlightItem(dataset) {
|
onHighlightItem(dataset) {
|
||||||
this.setState({ highlightedItem: dataset });
|
this.setState({ highlightedItem: dataset });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
if (this.props.error) {
|
||||||
<table id="tblDatasetList" className="studyListToolbar table noselect">
|
return <p>{this.props.error}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingIcon = (
|
||||||
|
<Icon name="circle-notch" className="loading-icon-spin loading-icon" />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.props.loading) {
|
||||||
|
return loadingIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = (
|
||||||
<tbody id="DatasetList">
|
<tbody id="DatasetList">
|
||||||
{this.props.datasets.map(dataset => {
|
{this.props.datasets.map(this.renderTableRow)}
|
||||||
return this.renderTableRow(dataset);
|
|
||||||
})}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table id="tblDatasetList" className="gcp-table table noselect">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{this.props.t('Dataset')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{this.props.datasets && body}
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(DatasetsList);
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import DicomUploader from './DicomUploader';
|
|
||||||
|
|
||||||
class DicomFileUploader extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
url: PropTypes.string,
|
|
||||||
oidcStorageKey: PropTypes.string.isRequired,
|
|
||||||
onClose: PropTypes.func,
|
|
||||||
};
|
|
||||||
state = {
|
|
||||||
uploaded: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.element = React.createRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.props.url != null) {
|
|
||||||
return (
|
|
||||||
<div className="gcp-window">
|
|
||||||
<DicomUploader
|
|
||||||
url={this.props.url}
|
|
||||||
oidcKey={this.props.oidcStorageKey}
|
|
||||||
></DicomUploader>
|
|
||||||
<button className="btn btn-primary" onClick={this.props.onClose}>
|
|
||||||
close
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DicomFileUploader;
|
|
||||||
49
src/googleCloud/DicomFileUploaderModal.js
Normal file
49
src/googleCloud/DicomFileUploaderModal.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Modal from 'react-bootstrap-modal';
|
||||||
|
import DicomUploader from './DicomUploader';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
class DicomFileUploaderModal extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
url: PropTypes.string,
|
||||||
|
oidcStorageKey: PropTypes.string.isRequired,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
uploaded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.props.url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
show={this.props.isOpen}
|
||||||
|
onHide={this.props.onClose}
|
||||||
|
aria-labelledby="ModalHeader"
|
||||||
|
className="modal fade themed in"
|
||||||
|
backdrop={false}
|
||||||
|
size={'md'}
|
||||||
|
keyboard={true}
|
||||||
|
>
|
||||||
|
<Modal.Header closeButton>
|
||||||
|
<Modal.Title>
|
||||||
|
{this.props.t('Google Cloud Healthcare API - DICOM Upload')}
|
||||||
|
</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
<DicomUploader
|
||||||
|
url={this.props.url}
|
||||||
|
oidcKey={this.props.oidcStorageKey}
|
||||||
|
/>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(DicomFileUploaderModal);
|
||||||
@ -1,31 +1,33 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { Icon } from 'react-viewerbase';
|
||||||
|
|
||||||
export default class DicomStoreList extends Component {
|
class DicomStoreList extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
search: '',
|
search: '',
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
stores: PropTypes.array,
|
stores: PropTypes.array,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
renderTableRow(store) {
|
static defaultProps = {
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTableRow = store => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={store.name}
|
key={store.name}
|
||||||
className={
|
className={
|
||||||
this.state.highlightedItem === store.name
|
this.state.highlightedItem === store.name
|
||||||
? 'studylistStudy noselect active'
|
? 'noselect active'
|
||||||
: 'studylistStudy noselect'
|
: 'noselect'
|
||||||
}
|
}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
this.onHighlightItem(store.name);
|
this.onHighlightItem(store.name);
|
||||||
@ -37,21 +39,40 @@ export default class DicomStoreList extends Component {
|
|||||||
<td className="project">{store.name.split('/')[7]}</td>
|
<td className="project">{store.name.split('/')[7]}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
onHighlightItem(store) {
|
onHighlightItem(store) {
|
||||||
this.setState({ highlightedItem: store });
|
this.setState({ highlightedItem: store });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if (this.props.error) {
|
||||||
|
return <p>{this.props.error}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingIcon = (
|
||||||
|
<Icon name="circle-notch" className="loading-icon-spin loading-icon" />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.props.loading) {
|
||||||
|
return loadingIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = (
|
||||||
|
<tbody id="StoreList">{this.props.stores.map(this.renderTableRow)}</tbody>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table id="tblStoreList" className="studyListToolbar table noselect">
|
<table id="tblStoreList" className="gcp-table table noselect">
|
||||||
<tbody id="StoreList">
|
<thead>
|
||||||
{this.props.stores.map(store => {
|
<tr>
|
||||||
return this.renderTableRow(store);
|
<th>{this.props.t('DICOM Store')}</th>
|
||||||
})}
|
</tr>
|
||||||
</tbody>
|
</thead>
|
||||||
|
{this.props.stores && body}
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(DicomStoreList);
|
||||||
|
|||||||
@ -5,33 +5,36 @@ import DicomStoreList from './DicomStoreList';
|
|||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
|
||||||
export default class DicomStorePicker extends Component {
|
export default class DicomStorePicker extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
error: null,
|
error: null,
|
||||||
loading: false,
|
loading: true,
|
||||||
stores: [],
|
stores: [],
|
||||||
locations: [],
|
locations: [],
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dataset: PropTypes.object,
|
dataset: PropTypes.object,
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const { authority, client_id } = window.config.oidc[0];
|
const { authority, client_id } = window.config.oidc[0];
|
||||||
const oidcStorageKey = `oidc.user:${authority}:${client_id}`;
|
const oidcStorageKey = `oidc.user:${authority}:${client_id}`;
|
||||||
api.setOidcStorageKey(oidcStorageKey);
|
api.setOidcStorageKey(oidcStorageKey);
|
||||||
const response = await api.loadDicomStores(this.props.dataset.name);
|
const response = await api.loadDicomStores(this.props.dataset.name);
|
||||||
this.loading = false;
|
|
||||||
if (response.isError) {
|
if (response.isError) {
|
||||||
this.error = response.message;
|
this.setState({
|
||||||
|
error: response.message,
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ stores: response.data.dicomStores || [] });
|
|
||||||
|
this.setState({
|
||||||
|
stores: response.data.dicomStores || [],
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -44,7 +47,7 @@ export default class DicomStorePicker extends Component {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
></DicomStoreList>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/googleCloud/DicomStorePickerModal.js
Normal file
67
src/googleCloud/DicomStorePickerModal.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Modal from 'react-bootstrap-modal';
|
||||||
|
import DatasetSelector from './DatasetSelector';
|
||||||
|
import './googleCloud.css';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
class DicomStorePickerModal extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
url: PropTypes.string,
|
||||||
|
oidcStorageKey: PropTypes.string.isRequired,
|
||||||
|
setServers: PropTypes.func.isRequired,
|
||||||
|
isOpen: PropTypes.bool.isRequired,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
isOpen: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleEvent = data => {
|
||||||
|
const servers = [
|
||||||
|
{
|
||||||
|
name: data.dicomStore,
|
||||||
|
imageRendering: 'wadors',
|
||||||
|
thumbnailRendering: 'wadors',
|
||||||
|
qidoSupportsIncludeField: false,
|
||||||
|
type: 'dicomWeb',
|
||||||
|
qidoRoot: data.qidoRoot,
|
||||||
|
wadoRoot: data.wadoRoot,
|
||||||
|
wadoUriRoot: data.wadoUriRoot,
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
this.props.setServers(servers);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
show={this.props.isOpen}
|
||||||
|
onHide={this.props.onClose}
|
||||||
|
aria-labelledby="ModalHeader"
|
||||||
|
className="modal fade themed in"
|
||||||
|
backdrop={false}
|
||||||
|
size={'md'}
|
||||||
|
keyboard={true}
|
||||||
|
>
|
||||||
|
<Modal.Header closeButton>
|
||||||
|
<Modal.Title>
|
||||||
|
{this.props.t('Google Cloud Healthcare API')}
|
||||||
|
</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
<DatasetSelector
|
||||||
|
setServers={this.handleEvent}
|
||||||
|
oidcKey={this.props.oidcStorageKey}
|
||||||
|
url={this.props.url}
|
||||||
|
/>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(DicomStorePickerModal);
|
||||||
@ -1,57 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import DatasetSelector from './DatasetSelector';
|
|
||||||
import './googleCloud.css';
|
|
||||||
|
|
||||||
class DicomStorePickerWindow extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
url: PropTypes.string,
|
|
||||||
oidcStorageKey: PropTypes.string.isRequired,
|
|
||||||
setServers: PropTypes.func.isRequired,
|
|
||||||
onClose: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.element = React.createRef();
|
|
||||||
this.handleEvent = this.handleEvent.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {}
|
|
||||||
|
|
||||||
handleEvent(data) {
|
|
||||||
const servers = [
|
|
||||||
{
|
|
||||||
name: data.dicomStore,
|
|
||||||
imageRendering: 'wadors',
|
|
||||||
thumbnailRendering: 'wadors',
|
|
||||||
qidoSupportsIncludeField: false,
|
|
||||||
requestOptions: { requestFromBrowser: true },
|
|
||||||
type: 'dicomWeb',
|
|
||||||
qidoRoot: data.qidoRoot,
|
|
||||||
wadoRoot: data.wadoRoot,
|
|
||||||
wadoUriRoot: data.wadoUriRoot,
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
this.props.setServers(servers);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="gcp-window">
|
|
||||||
<DatasetSelector
|
|
||||||
setServers={this.handleEvent}
|
|
||||||
oidcKey={this.props.oidcStorageKey}
|
|
||||||
url={this.props.url}
|
|
||||||
></DatasetSelector>
|
|
||||||
<button className="btn btn-primary" onClick={this.props.onClose}>
|
|
||||||
close
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DicomStorePickerWindow;
|
|
||||||
@ -6,9 +6,7 @@ import dicomUploader from './api/DicomUploadService';
|
|||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
|
||||||
export default class DicomUploader extends Component {
|
export default class DicomUploader extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
status: 'Upload',
|
status: 'Upload',
|
||||||
isCancelled: false,
|
isCancelled: false,
|
||||||
errorsCount: 0,
|
errorsCount: 0,
|
||||||
@ -21,10 +19,8 @@ export default class DicomUploader extends Component {
|
|||||||
totalCount: 0,
|
totalCount: 0,
|
||||||
successfullyUploadedCount: 0,
|
successfullyUploadedCount: 0,
|
||||||
lastFile: '',
|
lastFile: '',
|
||||||
uploadContext: null, // this is probably not needed, but we use this variable to destinguish between different downloads
|
uploadContext: null, // this is probably not needed, but we use this variable to distinguish between different downloads
|
||||||
};
|
};
|
||||||
this.uploadFiles = this.uploadFiles.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
@ -32,7 +28,6 @@ export default class DicomUploader extends Component {
|
|||||||
url: PropTypes.string,
|
url: PropTypes.string,
|
||||||
oidcKey: PropTypes.string,
|
oidcKey: PropTypes.string,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
filesLeft() {
|
filesLeft() {
|
||||||
return (
|
return (
|
||||||
@ -66,7 +61,7 @@ export default class DicomUploader extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadFiles(files) {
|
uploadFiles = files => {
|
||||||
const filesArray = Array.from(files.target.files);
|
const filesArray = Array.from(files.target.files);
|
||||||
const filesDict = {};
|
const filesDict = {};
|
||||||
filesArray.forEach((file, i) => {
|
filesArray.forEach((file, i) => {
|
||||||
@ -107,14 +102,14 @@ export default class DicomUploader extends Component {
|
|||||||
uploadCallback,
|
uploadCallback,
|
||||||
cancellationToken
|
cancellationToken
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
uploadCallback(fileId, error) {
|
uploadCallback(fileId, error) {
|
||||||
const file = this.state.files[fileId];
|
const file = this.state.files[fileId];
|
||||||
file.processed = true;
|
file.processed = true;
|
||||||
if (!error) {
|
if (!error) {
|
||||||
let uploadedVolume = this.state.uploadedVolume + file.size;
|
let uploadedVolume = this.state.uploadedVolume + file.size;
|
||||||
this.setState({ uploadedVolume: uploadedVolume });
|
this.setState({ uploadedVolume });
|
||||||
} else {
|
} else {
|
||||||
file.error = error;
|
file.error = error;
|
||||||
this.setState({ errorsCount: this.state.errorsCount + 1 });
|
this.setState({ errorsCount: this.state.errorsCount + 1 });
|
||||||
@ -122,17 +117,13 @@ export default class DicomUploader extends Component {
|
|||||||
this.setState({ lastFile: file.name });
|
this.setState({ lastFile: file.name });
|
||||||
let uploadedList = this.state.uploadedList;
|
let uploadedList = this.state.uploadedList;
|
||||||
uploadedList.push(file);
|
uploadedList.push(file);
|
||||||
this.setState({ uploadedList: uploadedList });
|
this.setState({ uploadedList });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTableRow(file) {
|
renderTableRow = file => {
|
||||||
let error = <></>;
|
let error = null;
|
||||||
if (file.error != null) {
|
if (file.error !== null) {
|
||||||
error = (
|
error = <p style={{ color: 'red' }}>{file.error}</p>;
|
||||||
<>
|
|
||||||
<font color="red">{file.error}</font>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<tr key={file.id}>
|
<tr key={file.id}>
|
||||||
@ -141,10 +132,10 @@ export default class DicomUploader extends Component {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.files == null) {
|
if (this.state.files === null) {
|
||||||
return (
|
return (
|
||||||
<div className="gcp-dicom-uploader">
|
<div className="gcp-dicom-uploader">
|
||||||
<div className="button">
|
<div className="button">
|
||||||
@ -177,13 +168,10 @@ export default class DicomUploader extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<table id="tblProjectList" className="table noselect">
|
||||||
<table
|
|
||||||
id="tblProjectList"
|
|
||||||
className="studyListToolbar table noselect"
|
|
||||||
>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="gcp-picker--path">
|
<th className="gcp-picker--path">
|
||||||
@ -192,13 +180,9 @@ export default class DicomUploader extends Component {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="ProjectList">
|
<tbody id="ProjectList">
|
||||||
{this.state.uploadedList.map(file => {
|
{this.state.uploadedList.map(this.renderTableRow)}
|
||||||
return this.renderTableRow(file);
|
|
||||||
})}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -5,14 +5,11 @@ import LocationsList from './LocationsList';
|
|||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
|
||||||
export default class LocationPicker extends Component {
|
export default class LocationPicker extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
error: null,
|
error: null,
|
||||||
loading: false,
|
loading: true,
|
||||||
locations: [],
|
locations: [],
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
project: PropTypes.object,
|
project: PropTypes.object,
|
||||||
@ -25,15 +22,19 @@ export default class LocationPicker extends Component {
|
|||||||
|
|
||||||
const response = await api.loadLocations(this.props.project.projectId);
|
const response = await api.loadLocations(this.props.project.projectId);
|
||||||
|
|
||||||
this.loading = false;
|
|
||||||
if (response.isError) {
|
if (response.isError) {
|
||||||
this.error = response.message;
|
this.setState({
|
||||||
|
error: response.message,
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ locations: response.data.locations || [] });
|
|
||||||
}
|
|
||||||
|
|
||||||
static defaultProps = {};
|
this.setState({
|
||||||
|
locations: response.data.locations || [],
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { locations, loading, error } = this.state;
|
const { locations, loading, error } = this.state;
|
||||||
@ -44,7 +45,7 @@ export default class LocationPicker extends Component {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
></LocationsList>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +1,33 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
export default class LocationsList extends Component {
|
import { withTranslation } from 'react-i18next';
|
||||||
constructor(props) {
|
import { Icon } from 'react-viewerbase';
|
||||||
super(props);
|
|
||||||
this.state = {
|
class LocationsList extends Component {
|
||||||
|
state = {
|
||||||
search: '',
|
search: '',
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
locations: PropTypes.array,
|
locations: PropTypes.array,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
renderTableRow(location) {
|
static defaultProps = {
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTableRow = location => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={location.locationId}
|
key={location.locationId}
|
||||||
className={
|
className={
|
||||||
this.state.highlightedItem === location.locationId
|
this.state.highlightedItem === location.locationId
|
||||||
? 'studylistStudy noselect active'
|
? 'noselect active'
|
||||||
: 'studylistStudy noselect'
|
: 'noselect'
|
||||||
}
|
}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
this.onHighlightItem(location.locationId);
|
this.onHighlightItem(location.locationId);
|
||||||
@ -36,21 +39,42 @@ export default class LocationsList extends Component {
|
|||||||
<td>{location.name.split('/')[3]}</td>
|
<td>{location.name.split('/')[3]}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
onHighlightItem(locationId) {
|
onHighlightItem(locationId) {
|
||||||
this.setState({ highlightedItem: locationId });
|
this.setState({ highlightedItem: locationId });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
if (this.props.error) {
|
||||||
<table id="tblLocationList" className="studyListToolbar table noselect">
|
return <p>{this.props.error}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingIcon = (
|
||||||
|
<Icon name="circle-notch" className="loading-icon-spin loading-icon" />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.props.loading) {
|
||||||
|
return loadingIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = (
|
||||||
<tbody id="LocationList">
|
<tbody id="LocationList">
|
||||||
{this.props.locations.map(project => {
|
{this.props.locations.map(this.renderTableRow)}
|
||||||
return this.renderTableRow(project);
|
|
||||||
})}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table id="tblLocationList" className="gcp-table table noselect">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{this.props.t('Location')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{this.props.locations && body}
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(LocationsList);
|
||||||
|
|||||||
@ -5,30 +5,33 @@ import ProjectsList from './ProjectsList';
|
|||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
|
||||||
export default class ProjectPicker extends Component {
|
export default class ProjectPicker extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
error: null,
|
error: null,
|
||||||
loading: false,
|
loading: true,
|
||||||
projects: [],
|
projects: [],
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
oidcKey: PropTypes.string,
|
oidcKey: PropTypes.string,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
api.setOidcStorageKey(this.props.oidcKey);
|
api.setOidcStorageKey(this.props.oidcKey);
|
||||||
const response = await api.loadProjects();
|
const response = await api.loadProjects();
|
||||||
this.loading = false;
|
|
||||||
if (response.isError) {
|
if (response.isError) {
|
||||||
this.error = response.message;
|
this.setState({
|
||||||
|
error: response.message,
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ projects: response.data.projects || [] });
|
|
||||||
|
this.setState({
|
||||||
|
projects: response.data.projects || [],
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -40,7 +43,7 @@ export default class ProjectPicker extends Component {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
></ProjectsList>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +1,35 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './googleCloud.css';
|
import './googleCloud.css';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { Icon } from 'react-viewerbase';
|
||||||
|
|
||||||
export default class ProjectsList extends Component {
|
class ProjectsList extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
search: '',
|
search: '',
|
||||||
highlightedItem: null,
|
highlightedItem: null,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
projects: PropTypes.array,
|
projects: PropTypes.array,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
|
t: PropTypes.func,
|
||||||
};
|
};
|
||||||
static defaultProps = {};
|
|
||||||
|
|
||||||
renderTableRow(project) {
|
static defaultProps = {
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTableRow = project => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={project.projectId}
|
key={project.projectId}
|
||||||
className={
|
className={
|
||||||
this.state.highlightedItem === project.projectId
|
this.state.highlightedItem === project.projectId
|
||||||
? 'studylistStudy noselect active'
|
? 'noselect active'
|
||||||
: 'studylistStudy noselect'
|
: 'noselect'
|
||||||
}
|
}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
this.onHighlightItem(project.projectId);
|
this.onHighlightItem(project.projectId);
|
||||||
@ -37,23 +40,46 @@ export default class ProjectsList extends Component {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<td>{project.name}</td>
|
<td>{project.name}</td>
|
||||||
|
<td>{project.projectId}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
onHighlightItem(project) {
|
onHighlightItem(project) {
|
||||||
this.setState({ highlightedItem: project });
|
this.setState({ highlightedItem: project });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
if (this.props.error) {
|
||||||
<table id="tblProjectList" className="studyListToolbar table noselect">
|
return <p>{this.props.error}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingIcon = (
|
||||||
|
<Icon name="circle-notch" className="loading-icon-spin loading-icon" />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.props.loading) {
|
||||||
|
return loadingIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = (
|
||||||
<tbody id="ProjectList">
|
<tbody id="ProjectList">
|
||||||
{this.props.projects.map(project => {
|
{this.props.projects.map(this.renderTableRow)}
|
||||||
return this.renderTableRow(project);
|
|
||||||
})}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table id="tblProjectList" className="gcp-table table noselect">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{this.props.t('Project')}</th>
|
||||||
|
<th>{this.props.t('ID')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{this.props.projects && body}
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTranslation('Common')(ProjectsList);
|
||||||
|
|||||||
@ -62,8 +62,8 @@ class DicomUploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readFile(file) {
|
readFile(file) {
|
||||||
const promise = new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
resolve({
|
resolve({
|
||||||
name: file.name,
|
name: file.name,
|
||||||
@ -75,7 +75,6 @@ class DicomUploadService {
|
|||||||
reader.onerror = error => reject(error);
|
reader.onerror = error => reject(error);
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
});
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getClient(url) {
|
getClient(url) {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class GoogleCloudApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async doRequest(urlStr, config = {}, params = {}) {
|
async doRequest(urlStr, config = {}, params = {}) {
|
||||||
var url = new URL(urlStr);
|
const url = new URL(urlStr);
|
||||||
let data = null;
|
let data = null;
|
||||||
url.search = new URLSearchParams(params);
|
url.search = new URLSearchParams(params);
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class GoogleCloudApi {
|
|||||||
if (data.nextPageToken != null) {
|
if (data.nextPageToken != null) {
|
||||||
params.pageToken = data.nextPageToken;
|
params.pageToken = data.nextPageToken;
|
||||||
let subPage = await this.doRequest(urlStr, config, params);
|
let subPage = await this.doRequest(urlStr, config, params);
|
||||||
for (var key in data) {
|
for (let key in data) {
|
||||||
if (data.hasOwnProperty(key)) {
|
if (data.hasOwnProperty(key)) {
|
||||||
data[key] = data[key].concat(subPage.data[key]);
|
data[key] = data[key].concat(subPage.data[key]);
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ class GoogleCloudApi {
|
|||||||
return {
|
return {
|
||||||
isError: false,
|
isError: false,
|
||||||
status: response.status,
|
status: response.status,
|
||||||
data: data,
|
data,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@ -81,17 +81,17 @@ class GoogleCloudApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadLocations(projectId) {
|
async loadLocations(projectId) {
|
||||||
return this.doRequest(this.urlBaseProject + `/${projectId}/locations`);
|
return this.doRequest(`${this.urlBaseProject}/${projectId}/locations`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadDatasets(projectId, locationId) {
|
async loadDatasets(projectId, locationId) {
|
||||||
return this.doRequest(
|
return this.doRequest(
|
||||||
this.urlBaseProject + `/${projectId}/locations/${locationId}/datasets`
|
`${this.urlBaseProject}/${projectId}/locations/${locationId}/datasets`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadDicomStores(dataset) {
|
async loadDicomStores(dataset) {
|
||||||
return this.doRequest(this.urlBase + `/${dataset}/dicomStores`);
|
return this.doRequest(`${this.urlBase}/${dataset}/dicomStores`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,76 @@
|
|||||||
|
.loading-icon-spin {
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-icon {
|
||||||
|
font-size: 30px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gcp-table {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-spacing: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.gcp-table > tr {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
.gcp-table > thead {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.gcp-table > thead tr th {
|
||||||
|
padding: 0;
|
||||||
|
border-bottom: 1px solid var(--ui-border-color-active);
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
.gcp-table > tbody tr {
|
||||||
|
padding: 5px;
|
||||||
|
background-color: var(--ui-gray-darker);
|
||||||
|
}
|
||||||
|
.gcp-table > tbody tr:nth-child(even) {
|
||||||
|
background-color: var(--ui-gray-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gcp-table > tbody tr td {
|
||||||
|
padding: 8px;
|
||||||
|
height: $body-cell-height;
|
||||||
|
line-height: $body-cell-height;
|
||||||
|
color: var(--table-text-primary-color);
|
||||||
|
font-weight: 300;
|
||||||
|
border-top: 1px solid var(--ui-gray-lighter);
|
||||||
|
border-bottom: 1px solid var(--ui-gray-lighter);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.gcp-table > tbody tr td.emptyCell {
|
||||||
|
color: #516873;
|
||||||
|
}
|
||||||
|
.gcp-table > tbody tr td.emptyValue {
|
||||||
|
color: var(--ui-gray-light);
|
||||||
|
}
|
||||||
|
.gcp-table > tbody tr:hover,
|
||||||
|
.gcp-table > tbody tr:active,
|
||||||
|
.gcp-table > tbody tr.active {
|
||||||
|
background-color: var(--table-hover-color);
|
||||||
|
color: var(--text-primary-color);
|
||||||
|
}
|
||||||
|
.gcp-table > tbody tr:hover td,
|
||||||
|
.gcp-table > tbody tr:active td,
|
||||||
|
.gcp-table > tbody tr.active td {
|
||||||
|
border-top: 1px solid var(--ui-gray-lighter);
|
||||||
|
border-bottom: 1px solid var(--ui-gray-lighter);
|
||||||
|
background-color: var(--table-hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
.gcp-files-selector {
|
.gcp-files-selector {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -32,10 +105,37 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gcp-picker {
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
width: 650px;
|
||||||
|
height: 600px;
|
||||||
|
background-color: #161a1f;
|
||||||
|
padding: 20px 30px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gcp-dicom-picker__exit {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
right: 30px;
|
||||||
|
width: 14px !important;
|
||||||
|
height: 14px !important;
|
||||||
|
filter: opacity(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gcp-dicom-picker__exit:hover {
|
||||||
|
filter: opacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gcp-picker--btn {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.gcp-picker--title {
|
.gcp-picker--title {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 28px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
@ -44,6 +144,11 @@
|
|||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 28px;
|
font-weight: 28px;
|
||||||
text-align: leaft;
|
text-align: left;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gcp-dicom-uploader .button {
|
||||||
|
float: left;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import OHIF from 'ohif-core';
|
import OHIF from 'ohif-core';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
import { StudyList } from 'react-viewerbase';
|
import { StudyList } from 'react-viewerbase';
|
||||||
import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
|
import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@ -14,7 +15,6 @@ class StudyListWithData extends Component {
|
|||||||
studies: [],
|
studies: [],
|
||||||
error: null,
|
error: null,
|
||||||
modalComponentId: null,
|
modalComponentId: null,
|
||||||
showStudyList: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -47,7 +47,6 @@ class StudyListWithData extends Component {
|
|||||||
if (!this.props.server && window.config.enableGoogleCloudAdapter) {
|
if (!this.props.server && window.config.enableGoogleCloudAdapter) {
|
||||||
this.setState({
|
this.setState({
|
||||||
modalComponentId: 'DicomStorePicker',
|
modalComponentId: 'DicomStorePicker',
|
||||||
showStudyList: false,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.searchForStudies({
|
this.searchForStudies({
|
||||||
@ -64,7 +63,6 @@ class StudyListWithData extends Component {
|
|||||||
if (this.props.server !== prevProps.server) {
|
if (this.props.server !== prevProps.server) {
|
||||||
this.setState({
|
this.setState({
|
||||||
modalComponentId: null,
|
modalComponentId: null,
|
||||||
showStudyList: true,
|
|
||||||
searchData: null,
|
searchData: null,
|
||||||
studies: null,
|
studies: null,
|
||||||
});
|
});
|
||||||
@ -151,7 +149,6 @@ class StudyListWithData extends Component {
|
|||||||
openModal = modalComponentId => {
|
openModal = modalComponentId => {
|
||||||
this.setState({
|
this.setState({
|
||||||
modalComponentId,
|
modalComponentId,
|
||||||
showStudyList: false,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -167,10 +164,9 @@ class StudyListWithData extends Component {
|
|||||||
this.searchForStudies(searchData);
|
this.searchForStudies(searchData);
|
||||||
};
|
};
|
||||||
|
|
||||||
update = () => {
|
closeModals = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
modalComponentId: null,
|
modalComponentId: null,
|
||||||
showStudyList: true,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,49 +177,47 @@ class StudyListWithData extends Component {
|
|||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let healthCareApiButtons = '';
|
let healthCareApiButtons = null;
|
||||||
let healthCareApiWindows = '';
|
let healthCareApiWindows = null;
|
||||||
|
|
||||||
|
// TODO: This should probably be a prop
|
||||||
if (window.config.enableGoogleCloudAdapter) {
|
if (window.config.enableGoogleCloudAdapter) {
|
||||||
if (this.state.modalComponentId) {
|
|
||||||
if (this.state.modalComponentId === 'DicomStorePicker') {
|
|
||||||
healthCareApiWindows = (
|
|
||||||
<ConnectedDicomStorePicker onClose={this.update} />
|
|
||||||
);
|
|
||||||
} else if (this.state.modalComponentId === 'DicomFilesUploader') {
|
|
||||||
healthCareApiWindows = (
|
|
||||||
<ConnectedDicomFilesUploader onClose={this.update} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
healthCareApiWindows = (
|
healthCareApiWindows = (
|
||||||
<>
|
<>
|
||||||
<div className="col-md-4 col-md-offset-2 layoutChooser pagination-area">
|
<ConnectedDicomStorePicker
|
||||||
{healthCareApiWindows}
|
isOpen={this.state.modalComponentId === 'DicomStorePicker'}
|
||||||
</div>
|
onClose={this.closeModals}
|
||||||
|
/>
|
||||||
|
<ConnectedDicomFilesUploader
|
||||||
|
isOpen={this.state.modalComponentId === 'DicomFilesUploader'}
|
||||||
|
onClose={this.closeModals}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
healthCareApiButtons = (
|
healthCareApiButtons = (
|
||||||
<>
|
<div
|
||||||
<div className="form-inline form-group pull-right">
|
className="form-inline btn-group pull-right"
|
||||||
|
style={{ padding: '20px' }}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
onClick={() => this.openModal('DicomStorePicker')}
|
onClick={() => this.openModal('DicomStorePicker')}
|
||||||
>
|
>
|
||||||
Change Dicom Store
|
{this.props.t('Change DICOM Store')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
onClick={() => this.openModal('DicomFilesUploader')}
|
onClick={() => this.openModal('DicomFilesUploader')}
|
||||||
>
|
>
|
||||||
Upload Studies
|
{this.props.t('Upload Studies')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let studyList = <></>;
|
|
||||||
studyList = (
|
const studyList = (
|
||||||
<div name="paginationArea">
|
<div className="paginationArea">
|
||||||
<StudyList
|
<StudyList
|
||||||
studies={this.state.studies}
|
studies={this.state.studies}
|
||||||
studyListFunctionsEnabled={false}
|
studyListFunctionsEnabled={false}
|
||||||
@ -250,4 +244,4 @@ class StudyListWithData extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(StudyListWithData);
|
export default withRouter(withTranslation('Common')(StudyListWithData));
|
||||||
|
|||||||
46
yarn.lock
46
yarn.lock
@ -4313,7 +4313,7 @@ debug@3.2.6, debug@^3.1.0, debug@^3.2.5, debug@^3.2.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "^2.1.1"
|
ms "^2.1.1"
|
||||||
|
|
||||||
debuglog@*, debuglog@^1.0.1:
|
debuglog@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
||||||
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
|
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
|
||||||
@ -6958,7 +6958,7 @@ import-local@^2.0.0:
|
|||||||
pkg-dir "^3.0.0"
|
pkg-dir "^3.0.0"
|
||||||
resolve-cwd "^2.0.0"
|
resolve-cwd "^2.0.0"
|
||||||
|
|
||||||
imurmurhash@*, imurmurhash@^0.1.4:
|
imurmurhash@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||||
@ -8602,7 +8602,7 @@ libnpm@^2.0.1:
|
|||||||
read-package-json "^2.0.13"
|
read-package-json "^2.0.13"
|
||||||
stringify-package "^1.0.0"
|
stringify-package "^1.0.0"
|
||||||
|
|
||||||
libnpmaccess@*, libnpmaccess@^3.0.1:
|
libnpmaccess@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.1.tgz#5b3a9de621f293d425191aa2e779102f84167fa8"
|
resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.1.tgz#5b3a9de621f293d425191aa2e779102f84167fa8"
|
||||||
integrity sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA==
|
integrity sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA==
|
||||||
@ -8631,7 +8631,7 @@ libnpmhook@^5.0.2:
|
|||||||
get-stream "^4.0.0"
|
get-stream "^4.0.0"
|
||||||
npm-registry-fetch "^3.8.0"
|
npm-registry-fetch "^3.8.0"
|
||||||
|
|
||||||
libnpmorg@*, libnpmorg@^1.0.0:
|
libnpmorg@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.0.tgz#979b868c48ba28c5820e3bb9d9e73c883c16a232"
|
resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.0.tgz#979b868c48ba28c5820e3bb9d9e73c883c16a232"
|
||||||
integrity sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw==
|
integrity sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw==
|
||||||
@ -8656,7 +8656,7 @@ libnpmpublish@^1.1.0:
|
|||||||
semver "^5.5.1"
|
semver "^5.5.1"
|
||||||
ssri "^6.0.1"
|
ssri "^6.0.1"
|
||||||
|
|
||||||
libnpmsearch@*, libnpmsearch@^2.0.0:
|
libnpmsearch@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.1.tgz#eccc73a8fbf267d765d18082b85daa2512501f96"
|
resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.1.tgz#eccc73a8fbf267d765d18082b85daa2512501f96"
|
||||||
integrity sha512-K0yXyut9MHHCAH+DOiglQCpmBKPZXSUu76+BE2maSEfQN15OwNaA/Aiioe9lRFlVFOr7WcuJCY+VSl+gLi9NTA==
|
integrity sha512-K0yXyut9MHHCAH+DOiglQCpmBKPZXSUu76+BE2maSEfQN15OwNaA/Aiioe9lRFlVFOr7WcuJCY+VSl+gLi9NTA==
|
||||||
@ -8665,7 +8665,7 @@ libnpmsearch@*, libnpmsearch@^2.0.0:
|
|||||||
get-stream "^4.0.0"
|
get-stream "^4.0.0"
|
||||||
npm-registry-fetch "^3.8.0"
|
npm-registry-fetch "^3.8.0"
|
||||||
|
|
||||||
libnpmteam@*, libnpmteam@^1.0.1:
|
libnpmteam@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.1.tgz#ff704b1b6c06ea674b3b1101ac3e305f5114f213"
|
resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.1.tgz#ff704b1b6c06ea674b3b1101ac3e305f5114f213"
|
||||||
integrity sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg==
|
integrity sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg==
|
||||||
@ -8923,11 +8923,6 @@ lodash-es@^4.17.11:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.11.tgz#145ab4a7ac5c5e52a3531fb4f310255a152b4be0"
|
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.11.tgz#145ab4a7ac5c5e52a3531fb4f310255a152b4be0"
|
||||||
integrity sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q==
|
integrity sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q==
|
||||||
|
|
||||||
lodash._baseindexof@*:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
|
|
||||||
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
|
|
||||||
|
|
||||||
lodash._baseuniq@~4.6.0:
|
lodash._baseuniq@~4.6.0:
|
||||||
version "4.6.0"
|
version "4.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
|
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
|
||||||
@ -8936,33 +8931,11 @@ lodash._baseuniq@~4.6.0:
|
|||||||
lodash._createset "~4.0.0"
|
lodash._createset "~4.0.0"
|
||||||
lodash._root "~3.0.0"
|
lodash._root "~3.0.0"
|
||||||
|
|
||||||
lodash._bindcallback@*:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
|
|
||||||
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
|
|
||||||
|
|
||||||
lodash._cacheindexof@*:
|
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
|
|
||||||
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
|
|
||||||
|
|
||||||
lodash._createcache@*:
|
|
||||||
version "3.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
|
|
||||||
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
|
|
||||||
dependencies:
|
|
||||||
lodash._getnative "^3.0.0"
|
|
||||||
|
|
||||||
lodash._createset@~4.0.0:
|
lodash._createset@~4.0.0:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
|
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
|
||||||
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
|
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
|
||||||
|
|
||||||
lodash._getnative@*, lodash._getnative@^3.0.0:
|
|
||||||
version "3.9.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
|
|
||||||
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
|
|
||||||
|
|
||||||
lodash._reinterpolate@~3.0.0:
|
lodash._reinterpolate@~3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||||
@ -9038,11 +9011,6 @@ lodash.once@^4.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||||
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
|
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
|
||||||
|
|
||||||
lodash.restparam@*:
|
|
||||||
version "3.6.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
|
|
||||||
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
|
|
||||||
|
|
||||||
lodash.set@^4.3.2:
|
lodash.set@^4.3.2:
|
||||||
version "4.3.2"
|
version "4.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
|
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
|
||||||
@ -10125,7 +10093,7 @@ npm-pick-manifest@^2.2.3:
|
|||||||
npm-package-arg "^6.0.0"
|
npm-package-arg "^6.0.0"
|
||||||
semver "^5.4.1"
|
semver "^5.4.1"
|
||||||
|
|
||||||
npm-profile@*, npm-profile@^4.0.1:
|
npm-profile@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.1.tgz#d350f7a5e6b60691c7168fbb8392c3603583f5aa"
|
resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.1.tgz#d350f7a5e6b60691c7168fbb8392c3603583f5aa"
|
||||||
integrity sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA==
|
integrity sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA==
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user