Compare commits

..
Author SHA1 Message Date
ohif-bot 84f087bca4 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.2.8
 - @ohif/core@2.3.3
 - @ohif/viewer@3.4.3
2020-01-24 10:33:21 +00:00
Igor Octaviano a7e612eb88 refactor: 💡 Clean up JSON launch with DICOMWeb server (#1388)
* refactor: 💡 Clean up JSON launch with DICOMWeb server

Clean up JSON launch with DICOMWeb server

✅ Closes: #1387

* Remove test file

* parse seriesinstanceuids in query

* Add default studies

* Remove test file

* Cleanup retrievedata changes

* Set active server
2020-01-24 10:31:22 +00:00
Mirna Silva 9e3afda2f1 Merge pull request #1384 from mirnasilva/percy-ci-fix
Visual tests: Fixed ci config for visual tests (percy)
2020-01-20 11:13:24 -03:00
Mirna Silva 4d7a91a584 Merge branch 'master' into percy-ci-fix 2020-01-17 20:48:51 -03:00
Mirna Silva 1dc320edcd Fixed ci config for visual tests 2020-01-17 20:44:45 -03:00
ohif-bot 1d02f5485f chore(release): publish [skip ci]
- @ohif/viewer@3.4.2
2020-01-17 22:45:01 +00:00
Mirna Silva 4c9a977920 Merge pull request #1382 from OHIF/mirna/test/visual-tests
Percy fix for CI failure
2020-01-17 19:43:19 -03:00
Mirna Silva b5db09c25e Merge pull request #1383 from mirnasilva/percy-ci-fix
Percy ci fix
2020-01-17 19:14:16 -03:00
Mirna Silva 8dc4a5b82a Merge branch 'percy-ci-fix' of https://github.com/mirnasilva/Viewers into percy-ci-fix 2020-01-17 16:36:08 -03:00
Mirna Silva 44add9ce2f Fix for save measurements failure 2020-01-17 16:35:26 -03:00
Mirna Silva c19eceeede Merge pull request #1381 from mirnasilva/percy-ci-fix
Percy tests - fix for CI failure
2020-01-17 14:46:43 -03:00
Mirna Silva 72bc5a5ae5 Merge branch 'master' into percy-ci-fix 2020-01-17 14:45:13 -03:00
Mirna Silva dfdf46dbdd fix for CI failure 2020-01-17 14:31:53 -03:00
ohif-bot 571dff2c09 chore(release): publish [skip ci]
- @ohif/viewer@3.4.1
2020-01-15 14:16:43 +00:00
Gustavo André Lelis b9a66d4424 fix: 🐛 Metadata is being mistakenly purged (#1360)
Closes: #1326
2020-01-15 09:15:10 -05:00
ohif-bot 7ab2e3e60d chore(release): publish [skip ci]
- @ohif/viewer@3.4.0
2020-01-14 15:26:35 +00:00
mukhlin a5d6bc6a51 feat: Custom Healthcare API endpoint (#1367)
* Add ability to configure Google Cloud Healthcare API endpoint.

* Fixed bug in script.

* Fixed PR remark.

* Set Healthcare API endpoint in proper place.
2020-01-14 10:22:53 -05:00
21 changed files with 251 additions and 105 deletions

No files matched your search

+1 -2
View File
@@ -459,8 +459,7 @@ workflows:
working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build
# start server --> verify running --> percy + chrome + cypress
start: yarn run test:e2e:dist
spec: 'cypress/integration/visual-regression/**/*'
command: yarn run test:e2e:dist
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
no-workspace: true # Don't persist workspace
post-steps:
+23 -9
View File
@@ -1,17 +1,31 @@
#!/bin/bash
# If CLIENT_ID is specified, use the google.js configuration with the modified ID
if [ ! -z "$CLIENT_ID" ]
if [ -n "$CLIENT_ID" ] || [ -n "$HEALTHCARE_API_ENDPOINT" ]
then
echo "Google Cloud Healthcare $CLIENT_ID has been provided: "
echo $CLIENT_ID
echo "Updating config..."
# If CLIENT_ID is specified, use the google.js configuration with the modified ID
if [ -n "$CLIENT_ID" ]
then
echo "Google Cloud Healthcare \$CLIENT_ID has been provided: "
echo "$CLIENT_ID"
echo "Updating config..."
# - Use SED to replace the CLIENT_ID that is currently in google.js
sed -i -e "s/YOURCLIENTID.apps.googleusercontent.com/$CLIENT_ID/g" /usr/share/nginx/html/google.js
# - Use SED to replace the CLIENT_ID that is currently in google.js
sed -i -e "s/YOURCLIENTID.apps.googleusercontent.com/$CLIENT_ID/g" /usr/share/nginx/html/google.js
fi
# - Copy google.js to overwrite app-config.js
cp /usr/share/nginx/html/google.js /usr/share/nginx/html/app-config.js
# If HEALTHCARE_API_ENDPOINT is specified, use the google.js configuration with the modified endpoint
if [ -n "$HEALTHCARE_API_ENDPOINT" ]
then
echo "Google Cloud Healthcare \$HEALTHCARE_API_ENDPOINT has been provided: "
echo "$HEALTHCARE_API_ENDPOINT"
echo "Updating config..."
# - Use SED to replace the HEALTHCARE_API_ENDPOINT that is currently in google.js
sed -i -e "s+https://healthcare.googleapis.com/v1beta1+$HEALTHCARE_API_ENDPOINT+g" /usr/share/nginx/html/google.js
fi
# - Copy google.js to overwrite app-config.js
cp /usr/share/nginx/html/google.js /usr/share/nginx/html/app-config.js
fi
echo "Starting Nginx to serve the OHIF Viewer..."
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.2.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.7...@ohif/extension-vtk@1.2.8) (2020-01-24)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.2.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.2.6...@ohif/extension-vtk@1.2.7) (2020-01-08)
**Note:** Version bump only for package @ohif/extension-vtk
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-vtk",
"version": "1.2.7",
"version": "1.2.8",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
@@ -52,7 +52,7 @@
"react-vtkjs-viewport": "^0.3.9"
},
"devDependencies": {
"@ohif/core": "^2.3.2",
"@ohif/core": "^2.3.3",
"@ohif/ui": "^1.1.8",
"cornerstone-tools": "^4.9.0",
"cornerstone-wado-image-loader": "^3.0.0",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.3.3](https://github.com/OHIF/Viewers/compare/@ohif/core@2.3.2...@ohif/core@2.3.3) (2020-01-24)
**Note:** Version bump only for package @ohif/core
## [2.3.2](https://github.com/OHIF/Viewers/compare/@ohif/core@2.3.1...@ohif/core@2.3.2) (2020-01-06)
**Note:** Version bump only for package @ohif/core
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/core",
"version": "2.3.2",
"version": "2.3.3",
"description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team",
"license": "MIT",
@@ -11,6 +11,16 @@ const servers = (state = defaultState, action) => {
servers.forEach(s => (s.active = true));
return { ...state, servers };
case 'ACTIVATE_SERVER': {
const newServer = { ...action.server, active: true };
const newServers = state.servers;
newServers.forEach(s => (s.active = false));
return {
...state,
servers: uniqBy([...newServers, newServer], 'wadoRoot'),
};
}
case 'SET_SERVERS':
return { ...state, servers: action.servers };
+38
View File
@@ -3,6 +3,44 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.4.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.4.2...@ohif/viewer@3.4.3) (2020-01-24)
**Note:** Version bump only for package @ohif/viewer
## [3.4.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.4.1...@ohif/viewer@3.4.2) (2020-01-17)
**Note:** Version bump only for package @ohif/viewer
## [3.4.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.4.0...@ohif/viewer@3.4.1) (2020-01-15)
### Bug Fixes
* 🐛 Metadata is being mistakenly purged ([#1360](https://github.com/OHIF/Viewers/issues/1360)) ([b9a66d4](https://github.com/OHIF/Viewers/commit/b9a66d44241f2896ef184511287fb4984671e16d)), closes [#1326](https://github.com/OHIF/Viewers/issues/1326)
# [3.4.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.8...@ohif/viewer@3.4.0) (2020-01-14)
### Features
* Custom Healthcare API endpoint ([#1367](https://github.com/OHIF/Viewers/issues/1367)) ([a5d6bc6](https://github.com/OHIF/Viewers/commit/a5d6bc6a51784ed3a8a40d4ae773de9099f116b9))
## [3.3.8](https://github.com/OHIF/Viewers/compare/@ohif/viewer@3.3.7...@ohif/viewer@3.3.8) (2020-01-10)
**Note:** Version bump only for package @ohif/viewer
@@ -6,7 +6,8 @@ describe('OHIF Save Measurements', function() {
beforeEach(() => {
// Drags Study thumbnail into viewport
cy.get('[data-cy="thumbnail-list"]:nth-child(1)')
cy.get('[data-cy="thumbnail-list"]')
.contains('Rheuma')
.scrollIntoView()
.drag('.viewport-drop-target');
@@ -56,7 +57,9 @@ describe('OHIF Save Measurements', function() {
cy.get('.sb-success').should('be.visible');
// Reload the page
cy.reload();
cy.reload()
.wait(1000) //Wait page to load
.expectMinimumThumbnails(2); //wait all thumbnails to load
//Verify that recently added measurement was retrieved
cy.get('@measurementsBtn').click();
@@ -105,8 +108,7 @@ describe('OHIF Save Measurements', function() {
cy.get('.sb-error')
.should('be.visible')
.and('contains.text', 'Error while saving the measurements');
// Close message overlay
cy.get('.sb-closeIcon').click();
// Close Measurements panel
cy.get('@measurementsBtn').click();
});
@@ -135,7 +137,9 @@ describe('OHIF Save Measurements', function() {
.and('contains.text', 'Measurements were saved with success');
// Reload the page
cy.reload();
cy.reload()
.wait(1000) //Wait page to load
.expectMinimumThumbnails(2); //wait all thumbnails to load
//Verify that measurement for unsupported tool was not saved
cy.get('@measurementsBtn').click();
@@ -23,10 +23,12 @@ describe('Visual Regression - OHIF VTK Extension', () => {
beforeEach(() => {
cy.initVTKToolsAliases();
cy.wait(100); //Wait toolbar to finish loading
cy.wait(1000); //Wait toolbar to finish loading
});
afterEach(() => {
cy.wait(5000); //wait screen loads back after screenshot
//Select Exit 2D MPR button
cy.get('[data-cy="exit 2d mpr"]').should($btn => {
expect($btn).to.be.visible;
+1 -1
View File
@@ -168,7 +168,7 @@ Cypress.Commands.add(
);
Cypress.Commands.add('expectMinimumThumbnails', (seriesToWait = 1) => {
cy.get('[data-cy=thumbnail-list]', { timeout: 10000 }).should($itemList => {
cy.get('[data-cy=thumbnail-list]', { timeout: 20000 }).should($itemList => {
expect($itemList.length >= seriesToWait).to.be.true;
});
});
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/viewer",
"version": "3.3.8",
"version": "3.4.3",
"description": "OHIF Viewer",
"author": "OHIF Contributors",
"license": "MIT",
@@ -46,12 +46,12 @@
"dependencies": {
"@babel/runtime": "^7.5.5",
"@ffmpeg-installer/ffmpeg": "1.0.20",
"@ohif/core": "^2.3.2",
"@ohif/core": "^2.3.3",
"@ohif/extension-cornerstone": "^2.2.1",
"@ohif/extension-dicom-html": "^1.1.0",
"@ohif/extension-dicom-microscopy": "^0.50.6",
"@ohif/extension-dicom-pdf": "^1.0.1",
"@ohif/extension-vtk": "^1.2.7",
"@ohif/extension-vtk": "^1.2.8",
"@ohif/i18n": "^0.52.4",
"@ohif/ui": "^1.1.8",
"@tanem/react-nprogress": "^1.1.25",
+1
View File
@@ -2,6 +2,7 @@ window.config = {
routerBasename: '/',
whiteLabelling: {},
enableGoogleCloudAdapter: true,
healthcareApiEndpoint: 'https://healthcare.googleapis.com/v1beta1',
servers: {
// This is an array, but we'll only use the first entry for now
dicomWeb: [],
@@ -0,0 +1,21 @@
import { connect } from 'react-redux';
import StandaloneRouting from '../routes/StandaloneRouting';
const mapDispatchToProps = dispatch => {
return {
activateServer: server => {
const action = {
type: 'ACTIVATE_SERVER',
server,
};
dispatch(action);
},
};
};
const ConnectedStandaloneRouting = connect(
null,
mapDispatchToProps
)(StandaloneRouting);
export default ConnectedStandaloneRouting;
@@ -2,23 +2,21 @@ import { connect } from 'react-redux';
import ViewerRetrieveStudyData from './ViewerRetrieveStudyData.js';
import OHIF from "@ohif/core";
const {
clearViewportSpecificData
} = OHIF.redux.actions;
const { clearViewportSpecificData } = OHIF.redux.actions;
const isActive = a => a.active === true;
const mapStateToProps = state => {
const mapStateToProps = (state, ownProps) => {
const activeServer = state.servers.servers.find(isActive);
return {
server: activeServer,
server: ownProps.server || activeServer,
};
};
const mapDispatchToProps = dispatch => {
return {
clearViewportSpecificData: () => {
dispatch(clearViewportSpecificData());
}
},
};
};
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useContext } from 'react';
import { metadata, studies, utils, log } from '@ohif/core';
import usePrevious from '../customHooks/usePrevious';
import ConnectedViewer from './ConnectedViewer.js';
import PropTypes from 'prop-types';
@@ -128,9 +129,9 @@ const _addSeriesToStudy = (studyMetadata, series) => {
const _updateMetaDataManager = (study, studyMetadata, series) => {
updateMetaDataManager(study, series);
const { studyInstanceUID } = study;
const { studyInstanceUid } = study;
if (!studyMetadataManager.get(studyInstanceUID)) {
if (!studyMetadataManager.get(studyInstanceUid)) {
studyMetadataManager.add(studyMetadata);
}
};
@@ -314,9 +315,15 @@ function ViewerRetrieveStudyData({
}
};
const prevStudyInstanceUids = usePrevious(studyInstanceUids);
useEffect(() => {
studyMetadataManager.purge();
purgeCancellablePromises();
const hasStudyInstanceUidsChanged = !(prevStudyInstanceUids && prevStudyInstanceUids.every(e => studyInstanceUids.includes(e)));
if (hasStudyInstanceUidsChanged) {
studyMetadataManager.purge();
purgeCancellablePromises();
}
}, [studyInstanceUids]);
useEffect(() => {
@@ -18,6 +18,7 @@ const getActiveServer = servers => {
const getServers = (appConfig, project, location, dataset, dicomStore) => {
let servers = [];
if (appConfig.enableGoogleCloudAdapter) {
GoogleCloudApi.urlBase = appConfig.healthcareApiEndpoint;
const pathUrl = GoogleCloudApi.getUrlBaseDicomWeb(
project,
location,
@@ -15,7 +15,11 @@ class GoogleCloudApi {
}
get urlBase() {
return `https://healthcare.googleapis.com/v1beta1`;
return this.healthcareApiEndpoint || 'https://healthcare.googleapis.com/v1beta1';
}
set urlBase(url) {
this.healthcareApiEndpoint = url;
}
get urlBaseProject() {
+7 -5
View File
@@ -2,14 +2,16 @@ import React from 'react';
import './NotFound.css';
import { Link } from 'react-router-dom';
export default function NotFound() {
export default function NotFound({ message = 'Sorry, this page does not exist.', showGoBackButton = true }) {
return (
<div className={'not-found'}>
<div>
<h4>Sorry, this page does not exist.</h4>
<h5>
<Link to={'/'}>Go back to the Study List</Link>
</h5>
<h4>{message}</h4>
{showGoBackButton && (
<h5>
<Link to={'/'}>Go back to the Study List</Link>
</h5>
)}
</div>
</div>
);
+93 -64
View File
@@ -1,29 +1,33 @@
import React, { Component } from 'react';
import { log, metadata, studies, utils } from '@ohif/core';
import { log, metadata, utils } from '@ohif/core';
import PropTypes from 'prop-types';
import ConnectedViewer from '../connectedComponents/ConnectedViewer';
import { extensionManager } from './../App.js';
import qs from 'querystring';
const { OHIFStudyMetadata } = metadata;
const { retrieveStudiesMetadata } = studies;
import { extensionManager } from './../App.js';
import ConnectedViewer from '../connectedComponents/ConnectedViewer';
import ConnectedViewerRetrieveStudyData from '../connectedComponents/ConnectedViewerRetrieveStudyData';
import NotFound from '../routes/NotFound';
const { studyMetadataManager, updateMetaDataManager } = utils;
const { OHIFStudyMetadata } = metadata;
class StandaloneRouting extends Component {
state = {
studies: null,
server: null,
studyInstanceUids: null,
seriesInstanceUids: null,
error: null,
loading: true,
};
studyInstanceUids = [];
static propTypes = {
location: PropTypes.object,
store: PropTypes.object,
setServers: PropTypes.func,
};
static parseQueryAndFetchStudies(query) {
parseQueryAndRetrieveDICOMWebData(query) {
return new Promise((resolve, reject) => {
const url = query.url;
@@ -43,7 +47,11 @@ class StandaloneRouting extends Component {
// When the JSON has been returned, parse it into a JavaScript Object
// and render the OHIF Viewer with this data
oReq.addEventListener('load', () => {
oReq.addEventListener('load', event => {
if (event.target.status === 404) {
reject(new Error('No JSON data found'));
}
// Parse the response content
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText
if (!oReq.responseText) {
@@ -54,27 +62,24 @@ class StandaloneRouting extends Component {
log.info(JSON.stringify(oReq.responseText, null, 2));
const data = JSON.parse(oReq.responseText);
if (data.servers && query.studyInstanceUids) {
if (data.servers) {
if (!query.studyInstanceUids) {
log.warn('No study instance uids specified');
reject(new Error('No study instance uids specified'));
}
const server = data.servers.dicomWeb[0];
server.type = 'dicomWeb';
const studyInstanceUids = query.studyInstanceUids.split(';');
const seriesInstanceUids = [];
log.warn('Activating server', server);
this.props.activateServer(server);
retrieveStudiesMetadata(
server,
studyInstanceUids,
seriesInstanceUids
).then(
studies => {
resolve(studies);
},
error => {
reject(error);
}
);
const studyInstanceUids = query.studyInstanceUids.split(';');
const seriesInstanceUids = query.seriesInstanceUids ? query.seriesInstanceUids.split(';') : [];
resolve({ server, studyInstanceUids, seriesInstanceUids });
} else {
resolve(data.studies);
resolve({ studies: data.studies, studyInstanceUids: [] });
}
});
@@ -96,56 +101,80 @@ class StandaloneRouting extends Component {
// Remove ? prefix which is included for some reason
search = search.slice(1, search.length);
const query = qs.parse(search);
const studies = await StandaloneRouting.parseQueryAndFetchStudies(query);
studyMetadataManager.purge();
let {
server,
studies,
studyInstanceUids,
seriesInstanceUids,
} = await this.parseQueryAndRetrieveDICOMWebData(query);
// Map studies to new format, update metadata manager?
const uniqueStudyUids = new Set();
const updatedStudies = studies.map(study => {
const studyMetadata = new OHIFStudyMetadata(
study,
study.studyInstanceUid
);
const sopClassHandlerModules =
extensionManager.modules['sopClassHandlerModule'];
if (studies) {
const {
studies: updatedStudies,
studyInstanceUids: updatedStudiesInstanceUids,
} = _mapStudiesToNewFormat(studies);
studies = updatedStudies;
studyInstanceUids = updatedStudiesInstanceUids;
}
study.displaySets =
study.displaySets ||
studyMetadata.createDisplaySets(sopClassHandlerModules);
studyMetadata.setDisplaySets(study.displaySets);
// Updates WADO-RS metaDataManager
updateMetaDataManager(study);
studyMetadataManager.add(studyMetadata);
uniqueStudyUids.add(study.studyInstanceUid);
return study;
this.setState({
studies,
server,
studyInstanceUids,
seriesInstanceUids,
loading: false,
});
this.studyInstanceUids = Array.from(uniqueStudyUids);
this.setState({ studies: updatedStudies });
} catch (error) {
this.setState({ error });
this.setState({ error: error.message, loading: false });
}
}
render() {
if (this.state.error) {
return <div>Error: {JSON.stringify(this.state.error)}</div>;
} else if (!this.state.studies) {
return <div>Loading...</div>;
const message = this.state.error ? `Error: ${JSON.stringify(this.state.error)}` : 'Loading...';
if (this.state.error || this.state.loading) {
return <NotFound message={message} showGoBackButton={this.state.error} />;
}
return (
<ConnectedViewer
studies={this.state.studies}
studyInstanceUids={this.studyInstanceUids}
/>
);
return this.state.studies ? (
<ConnectedViewer studies={this.state.studies} />
) : (
<ConnectedViewerRetrieveStudyData
studyInstanceUids={this.state.studyInstanceUids}
seriesInstanceUids={this.state.seriesInstanceUids}
server={this.state.server}
/>
);
}
}
const _mapStudiesToNewFormat = studies => {
studyMetadataManager.purge();
/* Map studies to new format, update metadata manager? */
const uniqueStudyUids = new Set();
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);
uniqueStudyUids.add(study.studyInstanceUid);
return study;
});
return {
studies: updatedStudies,
studyInstanceUids: Array.from(uniqueStudyUids),
};
};
export default StandaloneRouting;
+1 -1
View File
@@ -19,7 +19,7 @@ const StudyListRouting = asyncComponent(() =>
)
);
const StandaloneRouting = asyncComponent(() =>
import(/* webpackChunkName: "StandaloneRouting" */ './StandaloneRouting.js')
import(/* webpackChunkName: "ConnectedStandaloneRouting" */ '../connectedComponents/ConnectedStandaloneRouting.js')
);
const ViewerLocalFileData = asyncComponent(() =>
import(