PWV-1: Fixing merging issues
This commit is contained in:
parent
481bf30a14
commit
db0602def7
@ -6,10 +6,10 @@ if (Meteor.isClient){
|
||||
},
|
||||
signIn: {
|
||||
displayFullName: true,
|
||||
destination: '/worklist'
|
||||
destination: '/studylist'
|
||||
},
|
||||
signUp: {
|
||||
destination: '/worklist'
|
||||
destination: '/studylist'
|
||||
},
|
||||
themeColors: {
|
||||
primary: ""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template name="app">
|
||||
<div class="topBar noselect {{#if onStudyList}}studyList{{/if}}">
|
||||
<div class="clearfix p-x-1 p-t-1">
|
||||
<div class="clearfix">
|
||||
<a target='_blank'
|
||||
class="brandSection pull-left"
|
||||
href="http://ohif.org">
|
||||
|
||||
@ -9,6 +9,8 @@ $expandedHeight = 160px
|
||||
|
||||
.topBar
|
||||
height: $topBarHeight
|
||||
overflow: hidden
|
||||
padding: 1rem $studyListPadding 0
|
||||
theme('color', '$textPrimaryColor')
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
transition(all 0.5s ease)
|
||||
@ -19,7 +21,7 @@ $expandedHeight = 160px
|
||||
text-decoration: none
|
||||
|
||||
.logoImage
|
||||
margin: 0 8px
|
||||
margin: 0 8px 0 0
|
||||
width: 30px
|
||||
|
||||
.logoText
|
||||
@ -53,12 +55,11 @@ $expandedHeight = 160px
|
||||
.brandSection
|
||||
height: 100%
|
||||
width: 80%
|
||||
padding-left: 50px
|
||||
line-height: $expandedHeight
|
||||
|
||||
.logoImage
|
||||
width: 50px
|
||||
margin: 0 20px
|
||||
margin: 0 20px 0 0
|
||||
|
||||
.logoText
|
||||
font-size: 30px
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
accounts-base@1.2.14
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
aldeed:schema-deny@1.1.0
|
||||
aldeed:schema-index@1.1.1
|
||||
aldeed:simple-schema@1.5.3
|
||||
aldeed:template-extension@4.0.0
|
||||
allow-deny@1.0.5
|
||||
arsnebula:reactive-promise@0.9.1
|
||||
autoupdate@1.3.12
|
||||
babel-compiler@6.13.0
|
||||
babel-runtime@0.1.13
|
||||
base64@1.0.10
|
||||
binary-heap@1.0.10
|
||||
blaze@2.2.0
|
||||
blaze-html-templates@1.0.5
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.0.11
|
||||
caching-compiler@1.1.8
|
||||
caching-html-compiler@1.0.7
|
||||
callback-hook@1.0.10
|
||||
check@1.2.4
|
||||
clinical:router@2.0.19
|
||||
clinical:router-location@2.1.0
|
||||
clinical:router-middleware-stack@2.1.2
|
||||
clinical:router-url@2.1.0
|
||||
coffeescript@1.11.1_2
|
||||
ddp@1.2.5
|
||||
ddp-client@1.3.2
|
||||
ddp-common@1.2.7
|
||||
ddp-rate-limiter@1.0.6
|
||||
ddp-server@1.3.11
|
||||
deps@1.0.12
|
||||
design@0.0.1
|
||||
diff-sequence@1.0.7
|
||||
ecmascript@0.5.9
|
||||
ecmascript-runtime@0.3.15
|
||||
ejson@1.0.13
|
||||
fastclick@1.0.13
|
||||
fortawesome:fontawesome@4.6.3
|
||||
geojson-utils@1.0.10
|
||||
gilbertwat:bootstrap3-daterangepicker@1.3.21_1
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.11
|
||||
htmljs@1.0.11
|
||||
http@1.2.10
|
||||
id-map@1.0.9
|
||||
iron:controller@1.0.12
|
||||
iron:core@1.0.11
|
||||
iron:dynamic-template@1.0.12
|
||||
iron:layout@1.0.12
|
||||
johdirr:meteor-git-rev@0.0.4
|
||||
jquery@1.11.10
|
||||
launch-screen@1.1.0
|
||||
livedata@1.0.18
|
||||
localstorage@1.0.12
|
||||
logging@1.1.16
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.6.0
|
||||
meteor-base@1.0.4
|
||||
meteor-platform@1.2.6
|
||||
minifier-css@1.2.15
|
||||
minifier-js@1.2.15
|
||||
minimongo@1.0.18
|
||||
mobile-experience@1.0.4
|
||||
mobile-status-bar@1.0.13
|
||||
modules@0.7.7
|
||||
modules-runtime@0.7.7
|
||||
momentjs:moment@2.15.2
|
||||
mongo@1.1.14
|
||||
mongo-id@1.0.6
|
||||
mrt:moment@2.8.1
|
||||
natestrauser:select2@4.0.3
|
||||
npm-mongo@2.2.11_2
|
||||
observe-sequence@1.0.14
|
||||
ohif:core@0.0.1
|
||||
ohif:cornerstone@0.0.1
|
||||
ohif:dicom-services@0.0.1
|
||||
ohif:hanging-protocols@0.0.1
|
||||
ohif:study-list@0.0.1
|
||||
ohif:viewerbase@0.0.1
|
||||
ohif:wadoproxy@0.0.1
|
||||
ordered-dict@1.0.9
|
||||
peppelg:bootstrap-3-modal@1.0.4
|
||||
practicalmeteor:chai@2.1.0_1
|
||||
practicalmeteor:loglevel@1.2.0_2
|
||||
promise@0.8.8
|
||||
raix:eventemitter@0.1.3
|
||||
random@1.0.10
|
||||
rate-limit@1.0.6
|
||||
reactive-dict@1.1.8
|
||||
reactive-var@1.0.11
|
||||
reload@1.1.11
|
||||
retry@1.0.9
|
||||
routepolicy@1.0.12
|
||||
service-configuration@1.0.11
|
||||
session@1.1.7
|
||||
shell-server@0.2.1
|
||||
silentcicero:jszip@0.0.4
|
||||
spacebars@1.0.13
|
||||
spacebars-compiler@1.0.13
|
||||
standard-app-packages@1.0.9
|
||||
standard-minifier-css@1.3.2
|
||||
standard-minifier-js@1.2.1
|
||||
stylus@2.513.6
|
||||
templating@1.2.15
|
||||
templating-compiler@1.2.15
|
||||
templating-runtime@1.2.15
|
||||
templating-tools@1.0.5
|
||||
tracker@1.1.1
|
||||
twbs:bootstrap@3.3.6
|
||||
ui@1.0.12
|
||||
underscore@1.0.10
|
||||
url@1.0.11
|
||||
validatejs@0.0.1
|
||||
webapp@1.3.12
|
||||
webapp-hashing@1.0.9
|
||||
@ -1,11 +1,11 @@
|
||||
<template name="ohifViewer">
|
||||
<div class="topBar noselect {{#if onStudyList}}studyList{{/if}}">
|
||||
<div class="clearfix p-x-1 p-t-1">
|
||||
<div class="clearfix">
|
||||
<a target='_blank'
|
||||
class="brandSection pull-left"
|
||||
href="http://ohif.org">
|
||||
<svg class="logoImage">
|
||||
<use xlink:href="/packages/viewerbase/assets/icons.svg#icon-ohif-logo"></use>
|
||||
<use xlink:href="/packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"></use>
|
||||
</svg>
|
||||
<div class="logoText">
|
||||
Open Health Imaging Foundation
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
|
||||
const worklistContentId = 'worklistTab';
|
||||
const studylistContentId = 'studylistTab';
|
||||
let lastContentId;
|
||||
|
||||
// Define the ViewerData global object
|
||||
@ -15,8 +15,8 @@ Template.ohifViewer.events({
|
||||
'click .js-toggle-studyList'() {
|
||||
const contentId = Session.get('activeContentId');
|
||||
|
||||
if (contentId !== worklistContentId) {
|
||||
switchToTab(worklistContentId);
|
||||
if (contentId !== studylistContentId) {
|
||||
switchToTab(studylistContentId);
|
||||
} else {
|
||||
switchToTab(lastContentId);
|
||||
}
|
||||
@ -35,7 +35,7 @@ Template.ohifViewer.helpers({
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentId === worklistContentId) {
|
||||
if (contentId === studylistContentId) {
|
||||
return 'Back to viewer';
|
||||
} else {
|
||||
lastContentId = contentId;
|
||||
@ -44,6 +44,6 @@ Template.ohifViewer.helpers({
|
||||
},
|
||||
|
||||
onStudyList() {
|
||||
return (Session.get('activeContentId') === 'worklistTab');
|
||||
return (Session.get('activeContentId') === 'studylistTab');
|
||||
}
|
||||
});
|
||||
|
||||
@ -9,6 +9,8 @@ $expandedHeight = 160px
|
||||
|
||||
.topBar
|
||||
height: $topBarHeight
|
||||
overflow: hidden
|
||||
padding: 1rem $studyListPadding 0
|
||||
theme('color', '$textPrimaryColor')
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
transition(all 0.5s ease)
|
||||
@ -19,7 +21,7 @@ $expandedHeight = 160px
|
||||
text-decoration: none
|
||||
|
||||
.logoImage
|
||||
margin: 0 8px
|
||||
margin: 0 8px 0 0
|
||||
width: 30px
|
||||
|
||||
.logoText
|
||||
@ -53,12 +55,11 @@ $expandedHeight = 160px
|
||||
.brandSection
|
||||
height: 100%
|
||||
width: 80%
|
||||
padding-left: 50px
|
||||
line-height: $expandedHeight
|
||||
|
||||
.logoImage
|
||||
width: 50px
|
||||
margin: 0 20px
|
||||
margin: 0 20px 0 0
|
||||
|
||||
.logoText
|
||||
font-size: 30px
|
||||
@ -69,7 +70,7 @@ $expandedHeight = 160px
|
||||
top: 5px
|
||||
left: 5px
|
||||
|
||||
#worklistTabs
|
||||
#studylistTabs
|
||||
height: "calc(100% - %s)" % $topBarHeight
|
||||
|
||||
.tab-pane
|
||||
|
||||
@ -19,7 +19,7 @@ Template.toolbarSection.helpers({
|
||||
value: instance.data.state,
|
||||
options: [{
|
||||
value: 'studies',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-studies',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-studies',
|
||||
svgWidth: 15,
|
||||
svgHeight: 13,
|
||||
bottomLabel: 'Series'
|
||||
@ -47,35 +47,35 @@ Template.toolbarSection.helpers({
|
||||
id: 'zoom',
|
||||
title: 'Zoom',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-zoom'
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-zoom'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'wwwc',
|
||||
title: 'Levels',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-levels'
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-levels'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'pan',
|
||||
title: 'Pan',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-pan'
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-pan'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'length',
|
||||
title: 'Length',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'annotate',
|
||||
title: 'Annotate',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-non-target'
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-non-target'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
|
||||
@ -6,10 +6,10 @@ if (Meteor.isClient){
|
||||
},
|
||||
signIn: {
|
||||
displayFullName: true,
|
||||
destination: '/worklist'
|
||||
destination: '/studylist'
|
||||
},
|
||||
signUp: {
|
||||
destination: '/worklist'
|
||||
destination: '/studylist'
|
||||
},
|
||||
themeColors: {
|
||||
primary: ""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template name="app">
|
||||
<div class="topBar noselect {{#if onStudyList}}studyList{{/if}}">
|
||||
<div class="clearfix p-x-1 p-t-1">
|
||||
<div class="clearfix">
|
||||
<a target='_blank'
|
||||
class="brandSection pull-left"
|
||||
href="http://ohif.org">
|
||||
|
||||
@ -9,6 +9,8 @@ $expandedHeight = 160px
|
||||
|
||||
.topBar
|
||||
height: $topBarHeight
|
||||
overflow: hidden
|
||||
padding: 1rem $studyListPadding 0
|
||||
theme('color', '$textPrimaryColor')
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
transition(all 0.5s ease)
|
||||
@ -19,7 +21,7 @@ $expandedHeight = 160px
|
||||
text-decoration: none
|
||||
|
||||
.logoImage
|
||||
margin: 0 8px
|
||||
margin: 0 8px 0 0
|
||||
width: 30px
|
||||
|
||||
.logoText
|
||||
@ -53,12 +55,11 @@ $expandedHeight = 160px
|
||||
.brandSection
|
||||
height: 100%
|
||||
width: 80%
|
||||
padding-left: 50px
|
||||
line-height: $expandedHeight
|
||||
|
||||
.logoImage
|
||||
width: 50px
|
||||
margin: 0 20px
|
||||
margin: 0 20px 0 0
|
||||
|
||||
.logoText
|
||||
font-size: 30px
|
||||
|
||||
@ -79,7 +79,7 @@ class Bounded {
|
||||
const result = {};
|
||||
|
||||
// Check if the element is the window
|
||||
if (element === window) {
|
||||
if (!element || element === window) {
|
||||
const $window = $(window);
|
||||
const width = $window.outerWidth();
|
||||
const height = $window.outerHeight();
|
||||
|
||||
@ -8,7 +8,7 @@ $themes['tide'] = {
|
||||
$uiStateErrorBorder: #993333
|
||||
$uiStateErrorText: #661111
|
||||
|
||||
$uiLightGray: #516873
|
||||
$uiGrayLight: #516873
|
||||
$uiGray: #263340
|
||||
$uiGrayDark: #16202B
|
||||
$uiGrayDarker: #151A1F
|
||||
|
||||
@ -8,7 +8,7 @@ $themes['tigerlilly'] = {
|
||||
$uiStateErrorBorder: #CC6666
|
||||
$uiStateErrorText: #661111
|
||||
|
||||
$uiLightGray: #516873
|
||||
$uiGrayLight: #516873
|
||||
$uiGray: #263340
|
||||
$uiGrayDark: #16202B
|
||||
$uiGrayDarker: #151A1F
|
||||
|
||||
@ -6,6 +6,8 @@ $toolbarHeight = 78px
|
||||
$toolbarDrawerHeight = 62px
|
||||
$studiesSidebarMenuWidth = 307px
|
||||
$lesionsSidebarMenuWidth = 323px
|
||||
$studyListPadding = 8%
|
||||
$studyListPaddingMediumScreen = 10px
|
||||
|
||||
// Fonts
|
||||
$logoFontFamily = "Sanchez"
|
||||
|
||||
@ -1,291 +1,291 @@
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
// Uses NodeJS 'net'
|
||||
// https://nodejs.org/api/net.html
|
||||
var net = Npm.require('net');
|
||||
var Socket = net.Socket;
|
||||
|
||||
Connection = function(options) {
|
||||
EventEmitter.call(this);
|
||||
this.options = Object.assign({
|
||||
maxPackageSize: C.DEFAULT_MAX_PACKAGE_SIZE,
|
||||
idle: false,
|
||||
reconnect: true,
|
||||
vr: {
|
||||
split: true
|
||||
}
|
||||
}, options);
|
||||
|
||||
this.reset();
|
||||
};
|
||||
|
||||
util.inherits(Connection, EventEmitter);
|
||||
|
||||
var StoreHandle = function() {
|
||||
EventEmitter.call(this);
|
||||
};
|
||||
|
||||
util.inherits(StoreHandle, EventEmitter);
|
||||
|
||||
Connection.prototype.reset = function() {
|
||||
this.defaultPeer = null;
|
||||
this.defaultServer = null;
|
||||
|
||||
_.each(this.peers, peerInfo => {
|
||||
_.each(peerInfo.sockets, socket => socket.emit('close'));
|
||||
});
|
||||
|
||||
this.peers = {};
|
||||
};
|
||||
|
||||
Connection.prototype.addPeer = function(options) {
|
||||
if (!options.aeTitle || !options.host || !options.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var peer = {
|
||||
host: options.host,
|
||||
port: options.port,
|
||||
sockets: {}
|
||||
};
|
||||
|
||||
this.peers[options.aeTitle] = peer;
|
||||
if (options.default) {
|
||||
if (options.server) {
|
||||
this.defaultServer = options.aeTitle;
|
||||
} else {
|
||||
this.defaultPeer = options.aeTitle;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.server) {
|
||||
//start listening
|
||||
peer.server = net.createServer();
|
||||
peer.server.listen(options.port, options.host, function() {
|
||||
console.log('listening on %j', this.address());
|
||||
});
|
||||
peer.server.on('error', function(err) {
|
||||
console.log('server error %j', err);
|
||||
});
|
||||
peer.server.on('connection', nativeSocket => {
|
||||
//incoming connections
|
||||
var socket = new CSocket(nativeSocket, this.options);
|
||||
this.addSocket(options.aeTitle, socket);
|
||||
|
||||
//close server on close socket
|
||||
socket.on('close', function() {
|
||||
peer.server.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Connection.prototype.selectPeer = function(aeTitle) {
|
||||
if (!aeTitle || !this.peers[aeTitle]) {
|
||||
throw 'No such peer';
|
||||
}
|
||||
|
||||
return this.peers[aeTitle];
|
||||
};
|
||||
|
||||
Connection.prototype._sendFile = function(socket, sHandle, file, maxSend, metaLength, list) {
|
||||
var fileNameText = typeof file.file === 'string' ? file.file : 'buffer';
|
||||
console.log('Sending file ' + fileNameText);
|
||||
var useContext = socket.getContextByUID(file.context);
|
||||
var self = this;
|
||||
|
||||
PDU.generatePDatas(useContext.id, file.file, maxSend, null, metaLength, function(err, handle) {
|
||||
if (err) {
|
||||
console.log('Error while sending file');
|
||||
return;
|
||||
}
|
||||
|
||||
var processNext = function() {
|
||||
var next = list.shift();
|
||||
if (next) {
|
||||
self._sendFile(socket, sHandle, next, maxSend, metaLength, list);
|
||||
} else {
|
||||
socket.release();
|
||||
}
|
||||
};
|
||||
|
||||
var store = socket.storeInstance(useContext.abstractSyntax, file.uid);
|
||||
handle.on('pdv', function(pdv) {
|
||||
socket.sendPData(pdv);
|
||||
});
|
||||
handle.on('error', function(err) {
|
||||
sHandle.emit('file', err, fileNameText);
|
||||
processNext();
|
||||
});
|
||||
store.on('response', function(msg) {
|
||||
var statusText = msg.getStatus().toString(16);
|
||||
console.log('STORE reponse with status', statusText);
|
||||
var error = null;
|
||||
if (msg.failure()) {
|
||||
error = new Error(statusText);
|
||||
}
|
||||
|
||||
sHandle.emit('file', error, fileNameText);
|
||||
processNext();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Connection.prototype.storeInstances = function(fileList) {
|
||||
var contexts = {};
|
||||
var read = 0;
|
||||
var length = fileList.length;
|
||||
var toSend = [];
|
||||
var self = this;
|
||||
var handle = new StoreHandle();
|
||||
var lastProcessedMetaLength;
|
||||
|
||||
fileList.forEach(function(bufferOrFile) {
|
||||
var fileNameText = typeof bufferOrFile === 'string' ? bufferOrFile : 'buffer';
|
||||
DicomMessage.readMetaHeader(bufferOrFile, function(err, metaMessage, metaLength) {
|
||||
read++;
|
||||
if (err) {
|
||||
handle.emit('file', err, fileNameText);
|
||||
if (read === length && toSend.length > 0 && lastProcessedMetaLength) {
|
||||
sendProcessedFiles(self, contexts, toSend, handle, lastProcessedMetaLength);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Dicom file ' + (typeof bufferOrFile === 'string' ? bufferOrFile : 'buffer') + ' found');
|
||||
lastProcessedMetaLength = metaLength;
|
||||
var syntax = metaMessage.getValue(0x00020010);
|
||||
var sopClassUID = metaMessage.getValue(0x00020002);
|
||||
var instanceUID = metaMessage.getValue(0x00020003);
|
||||
|
||||
if (!contexts[sopClassUID]) {
|
||||
contexts[sopClassUID] = [];
|
||||
}
|
||||
|
||||
if (syntax && contexts[sopClassUID].indexOf(syntax) === -1) {
|
||||
contexts[sopClassUID].push(syntax);
|
||||
}
|
||||
|
||||
toSend.push({
|
||||
file: bufferOrFile,
|
||||
context: sopClassUID,
|
||||
uid: instanceUID
|
||||
});
|
||||
|
||||
if (read === length) {
|
||||
sendProcessedFiles(self, contexts, toSend, handle, metaLength);
|
||||
}
|
||||
});
|
||||
});
|
||||
return handle;
|
||||
};
|
||||
|
||||
// Starts to send dcm files
|
||||
sendProcessedFiles = function(self, contexts, toSend, handle, metaLength) {
|
||||
var useContexts = [];
|
||||
_.each(contexts, (useSyntaxes, context) => {
|
||||
if (useSyntaxes.length > 0) {
|
||||
useContexts.push({
|
||||
context: context,
|
||||
syntaxes: useSyntaxes
|
||||
});
|
||||
} else {
|
||||
throw 'No syntax specified for context ' + context;
|
||||
}
|
||||
});
|
||||
|
||||
self.associate({
|
||||
contexts: useContexts
|
||||
}, function(ac) {
|
||||
var maxSend = ac.getMaxSize();
|
||||
var next = toSend.shift();
|
||||
self._sendFile(this, handle, next, maxSend, metaLength, toSend);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
Connection.prototype.storeResponse = function(messageId, msg) {
|
||||
var rq = this.messages[messageId];
|
||||
|
||||
if (rq.listener[2]) {
|
||||
var status = rq.listener[2].call(this, msg);
|
||||
if (status !== undefined && status !== null && rq.command.store) {
|
||||
//store ok, ready to send c-store-rsp
|
||||
var storeSr = rq.command.store;
|
||||
var replyMessage = storeSr.replyWith(status);
|
||||
replyMessage.setAffectedSOPInstanceUID(this.lastCommand.getSOPInstanceUID());
|
||||
replyMessage.setReplyMessageId(this.lastCommand.messageId);
|
||||
this.sendMessage(replyMessage, null, null, storeSr);
|
||||
} else {
|
||||
throw 'Missing store status';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Connection.prototype.allClosed = function() {
|
||||
var allClosed = true;
|
||||
for (var i in this.peers) {
|
||||
if (Object.keys(peers[i].sockets).length > 0) {
|
||||
allClosed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return allClosed;
|
||||
};
|
||||
|
||||
Connection.prototype.addSocket = function(hostAE, socket) {
|
||||
var peerInfo = this.selectPeer(hostAE);
|
||||
|
||||
peerInfo.sockets[socket.id] = socket;
|
||||
|
||||
socket.on('close', function() {
|
||||
if (peerInfo.sockets[this.id]) {
|
||||
delete peerInfo.sockets[this.id];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Connection.prototype.associate = function(options, callback) {
|
||||
var hostAE = options.hostAE ? options.hostAE : this.defaultPeer;
|
||||
var sourceAE = options.sourceAE ? options.sourceAE : this.defaultServer;
|
||||
|
||||
if (!hostAE || !sourceAE) {
|
||||
throw 'Peers not provided or no defaults in settings';
|
||||
}
|
||||
|
||||
var peerInfo = this.selectPeer(hostAE);
|
||||
var nativeSocket = new Socket();
|
||||
|
||||
var socket = new CSocket(nativeSocket, this.options);
|
||||
|
||||
if (callback) {
|
||||
socket.once('associated', callback);
|
||||
}
|
||||
|
||||
console.log('Starting Connection...');
|
||||
|
||||
socket.setCalledAe(hostAE);
|
||||
socket.setCallingAE(sourceAE);
|
||||
|
||||
console.log(peerInfo);
|
||||
|
||||
nativeSocket.connect({
|
||||
host: peerInfo.host,
|
||||
port: peerInfo.port
|
||||
}, () => {
|
||||
//connected
|
||||
this.addSocket(hostAE, socket);
|
||||
|
||||
if (options.contexts) {
|
||||
socket.setPresentationContexts(options.contexts);
|
||||
} else {
|
||||
throw 'Contexts must be specified';
|
||||
}
|
||||
|
||||
socket.associate();
|
||||
});
|
||||
|
||||
return socket;
|
||||
};
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
// Uses NodeJS 'net'
|
||||
// https://nodejs.org/api/net.html
|
||||
var net = Npm.require('net');
|
||||
var Socket = net.Socket;
|
||||
|
||||
Connection = function(options) {
|
||||
EventEmitter.call(this);
|
||||
this.options = Object.assign({
|
||||
maxPackageSize: C.DEFAULT_MAX_PACKAGE_SIZE,
|
||||
idle: false,
|
||||
reconnect: true,
|
||||
vr: {
|
||||
split: true
|
||||
}
|
||||
}, options);
|
||||
|
||||
this.reset();
|
||||
};
|
||||
|
||||
util.inherits(Connection, EventEmitter);
|
||||
|
||||
var StoreHandle = function() {
|
||||
EventEmitter.call(this);
|
||||
};
|
||||
|
||||
util.inherits(StoreHandle, EventEmitter);
|
||||
|
||||
Connection.prototype.reset = function() {
|
||||
this.defaultPeer = null;
|
||||
this.defaultServer = null;
|
||||
|
||||
_.each(this.peers, peerInfo => {
|
||||
_.each(peerInfo.sockets, socket => socket.emit('close'));
|
||||
});
|
||||
|
||||
this.peers = {};
|
||||
};
|
||||
|
||||
Connection.prototype.addPeer = function(options) {
|
||||
if (!options.aeTitle || !options.host || !options.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var peer = {
|
||||
host: options.host,
|
||||
port: options.port,
|
||||
sockets: {}
|
||||
};
|
||||
|
||||
this.peers[options.aeTitle] = peer;
|
||||
if (options.default) {
|
||||
if (options.server) {
|
||||
this.defaultServer = options.aeTitle;
|
||||
} else {
|
||||
this.defaultPeer = options.aeTitle;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.server) {
|
||||
//start listening
|
||||
peer.server = net.createServer();
|
||||
peer.server.listen(options.port, options.host, function() {
|
||||
console.log('listening on %j', this.address());
|
||||
});
|
||||
peer.server.on('error', function(err) {
|
||||
console.log('server error %j', err);
|
||||
});
|
||||
peer.server.on('connection', nativeSocket => {
|
||||
//incoming connections
|
||||
var socket = new CSocket(nativeSocket, this.options);
|
||||
this.addSocket(options.aeTitle, socket);
|
||||
|
||||
//close server on close socket
|
||||
socket.on('close', function() {
|
||||
peer.server.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Connection.prototype.selectPeer = function(aeTitle) {
|
||||
if (!aeTitle || !this.peers[aeTitle]) {
|
||||
throw 'No such peer';
|
||||
}
|
||||
|
||||
return this.peers[aeTitle];
|
||||
};
|
||||
|
||||
Connection.prototype._sendFile = function(socket, sHandle, file, maxSend, metaLength, list) {
|
||||
var fileNameText = typeof file.file === 'string' ? file.file : 'buffer';
|
||||
console.log('Sending file ' + fileNameText);
|
||||
var useContext = socket.getContextByUID(file.context);
|
||||
var self = this;
|
||||
|
||||
PDU.generatePDatas(useContext.id, file.file, maxSend, null, metaLength, function(err, handle) {
|
||||
if (err) {
|
||||
console.log('Error while sending file');
|
||||
return;
|
||||
}
|
||||
|
||||
var processNext = function() {
|
||||
var next = list.shift();
|
||||
if (next) {
|
||||
self._sendFile(socket, sHandle, next, maxSend, metaLength, list);
|
||||
} else {
|
||||
socket.release();
|
||||
}
|
||||
};
|
||||
|
||||
var store = socket.storeInstance(useContext.abstractSyntax, file.uid);
|
||||
handle.on('pdv', function(pdv) {
|
||||
socket.sendPData(pdv);
|
||||
});
|
||||
handle.on('error', function(err) {
|
||||
sHandle.emit('file', err, fileNameText);
|
||||
processNext();
|
||||
});
|
||||
store.on('response', function(msg) {
|
||||
var statusText = msg.getStatus().toString(16);
|
||||
console.log('STORE reponse with status', statusText);
|
||||
var error = null;
|
||||
if (msg.failure()) {
|
||||
error = new Error(statusText);
|
||||
}
|
||||
|
||||
sHandle.emit('file', error, fileNameText);
|
||||
processNext();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Connection.prototype.storeInstances = function(fileList) {
|
||||
var contexts = {};
|
||||
var read = 0;
|
||||
var length = fileList.length;
|
||||
var toSend = [];
|
||||
var self = this;
|
||||
var handle = new StoreHandle();
|
||||
var lastProcessedMetaLength;
|
||||
|
||||
fileList.forEach(function(bufferOrFile) {
|
||||
var fileNameText = typeof bufferOrFile === 'string' ? bufferOrFile : 'buffer';
|
||||
DicomMessage.readMetaHeader(bufferOrFile, function(err, metaMessage, metaLength) {
|
||||
read++;
|
||||
if (err) {
|
||||
handle.emit('file', err, fileNameText);
|
||||
if (read === length && toSend.length > 0 && lastProcessedMetaLength) {
|
||||
sendProcessedFiles(self, contexts, toSend, handle, lastProcessedMetaLength);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Dicom file ' + (typeof bufferOrFile === 'string' ? bufferOrFile : 'buffer') + ' found');
|
||||
lastProcessedMetaLength = metaLength;
|
||||
var syntax = metaMessage.getValue(0x00020010);
|
||||
var sopClassUID = metaMessage.getValue(0x00020002);
|
||||
var instanceUID = metaMessage.getValue(0x00020003);
|
||||
|
||||
if (!contexts[sopClassUID]) {
|
||||
contexts[sopClassUID] = [];
|
||||
}
|
||||
|
||||
if (syntax && contexts[sopClassUID].indexOf(syntax) === -1) {
|
||||
contexts[sopClassUID].push(syntax);
|
||||
}
|
||||
|
||||
toSend.push({
|
||||
file: bufferOrFile,
|
||||
context: sopClassUID,
|
||||
uid: instanceUID
|
||||
});
|
||||
|
||||
if (read === length) {
|
||||
sendProcessedFiles(self, contexts, toSend, handle, metaLength);
|
||||
}
|
||||
});
|
||||
});
|
||||
return handle;
|
||||
};
|
||||
|
||||
// Starts to send dcm files
|
||||
sendProcessedFiles = function(self, contexts, toSend, handle, metaLength) {
|
||||
var useContexts = [];
|
||||
_.each(contexts, (useSyntaxes, context) => {
|
||||
if (useSyntaxes.length > 0) {
|
||||
useContexts.push({
|
||||
context: context,
|
||||
syntaxes: useSyntaxes
|
||||
});
|
||||
} else {
|
||||
throw 'No syntax specified for context ' + context;
|
||||
}
|
||||
});
|
||||
|
||||
self.associate({
|
||||
contexts: useContexts
|
||||
}, function(ac) {
|
||||
var maxSend = ac.getMaxSize();
|
||||
var next = toSend.shift();
|
||||
self._sendFile(this, handle, next, maxSend, metaLength, toSend);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
Connection.prototype.storeResponse = function(messageId, msg) {
|
||||
var rq = this.messages[messageId];
|
||||
|
||||
if (rq.listener[2]) {
|
||||
var status = rq.listener[2].call(this, msg);
|
||||
if (status !== undefined && status !== null && rq.command.store) {
|
||||
//store ok, ready to send c-store-rsp
|
||||
var storeSr = rq.command.store;
|
||||
var replyMessage = storeSr.replyWith(status);
|
||||
replyMessage.setAffectedSOPInstanceUID(this.lastCommand.getSOPInstanceUID());
|
||||
replyMessage.setReplyMessageId(this.lastCommand.messageId);
|
||||
this.sendMessage(replyMessage, null, null, storeSr);
|
||||
} else {
|
||||
throw 'Missing store status';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Connection.prototype.allClosed = function() {
|
||||
var allClosed = true;
|
||||
for (var i in this.peers) {
|
||||
if (Object.keys(peers[i].sockets).length > 0) {
|
||||
allClosed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return allClosed;
|
||||
};
|
||||
|
||||
Connection.prototype.addSocket = function(hostAE, socket) {
|
||||
var peerInfo = this.selectPeer(hostAE);
|
||||
|
||||
peerInfo.sockets[socket.id] = socket;
|
||||
|
||||
socket.on('close', function() {
|
||||
if (peerInfo.sockets[this.id]) {
|
||||
delete peerInfo.sockets[this.id];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Connection.prototype.associate = function(options, callback) {
|
||||
var hostAE = options.hostAE ? options.hostAE : this.defaultPeer;
|
||||
var sourceAE = options.sourceAE ? options.sourceAE : this.defaultServer;
|
||||
|
||||
if (!hostAE || !sourceAE) {
|
||||
throw 'Peers not provided or no defaults in settings';
|
||||
}
|
||||
|
||||
var peerInfo = this.selectPeer(hostAE);
|
||||
var nativeSocket = new Socket();
|
||||
|
||||
var socket = new CSocket(nativeSocket, this.options);
|
||||
|
||||
if (callback) {
|
||||
socket.once('associated', callback);
|
||||
}
|
||||
|
||||
console.log('Starting Connection...');
|
||||
|
||||
socket.setCalledAe(hostAE);
|
||||
socket.setCallingAE(sourceAE);
|
||||
|
||||
console.log(peerInfo);
|
||||
|
||||
nativeSocket.connect({
|
||||
host: peerInfo.host,
|
||||
port: peerInfo.port
|
||||
}, () => {
|
||||
//connected
|
||||
this.addSocket(hostAE, socket);
|
||||
|
||||
if (options.contexts) {
|
||||
socket.setPresentationContexts(options.contexts);
|
||||
} else {
|
||||
throw 'Contexts must be specified';
|
||||
}
|
||||
|
||||
socket.associate();
|
||||
});
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
||||
@ -12,11 +12,10 @@ body
|
||||
|
||||
.studylistContainer
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
margin: 0 auto
|
||||
margin: 2px auto 0
|
||||
color: white
|
||||
float: left;
|
||||
width: 100%;
|
||||
|
||||
|
||||
.tab-content
|
||||
width: 100%
|
||||
height: calc(100% - 91px)
|
||||
@ -31,4 +30,4 @@ body
|
||||
|
||||
.viewerContainer
|
||||
height: 100%
|
||||
width: 100%
|
||||
width: 100%
|
||||
|
||||
@ -4,9 +4,6 @@
|
||||
font-size: 13px
|
||||
font-weight: normal !important
|
||||
|
||||
.rows-per-page
|
||||
padding-top: 20px
|
||||
|
||||
label
|
||||
font-weight: normal
|
||||
|
||||
@ -15,18 +12,23 @@
|
||||
color: white
|
||||
|
||||
.page-number
|
||||
margin: 0
|
||||
text-align: right
|
||||
|
||||
label
|
||||
font-weight: normal
|
||||
|
||||
ul#pagination
|
||||
margin: 0
|
||||
|
||||
li
|
||||
a
|
||||
padding: 4px 8px
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
theme('border-color', '$uiGray')
|
||||
theme('background-color', '$uiGrayDarkest')
|
||||
color: white
|
||||
padding: 4px 8px
|
||||
|
||||
&:hover
|
||||
theme('color', '$activeColor')
|
||||
@ -41,3 +43,13 @@
|
||||
a:hover
|
||||
color: inherit
|
||||
|
||||
&:not(.disabled):hover a
|
||||
theme('background-color', '$uiGrayDark')
|
||||
theme('color', '$activeColor')
|
||||
|
||||
&.active a
|
||||
theme('background-color', '$uiGrayDark')
|
||||
theme('color', '$activeColor')
|
||||
|
||||
&.disabled a
|
||||
theme('color', '$uiGrayLight')
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template name="studylistResult">
|
||||
<div class="studyListToolbar">
|
||||
<div class="header">
|
||||
<div class="studyListToolbar clearfix">
|
||||
<div class="header pull-left">
|
||||
Study list
|
||||
</div>
|
||||
<div class="studyCount pull-right">
|
||||
@ -104,4 +104,4 @@
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@ -8,23 +8,21 @@ $inputBackgroundColor = #2c363f
|
||||
$inputPlaceholderColor = lightgray
|
||||
|
||||
$studyListToolbarHeight = 75px
|
||||
$tablePadding = 8%
|
||||
$bodyCellHeight = 40px
|
||||
|
||||
.studyListToolbar
|
||||
theme('background', '$uiGrayDarker')
|
||||
height: $studyListToolbarHeight
|
||||
border-bottom: 2px solid black
|
||||
padding: 0 30px
|
||||
margin-bottom: 2px
|
||||
padding: 0 $studyListPadding
|
||||
|
||||
div
|
||||
&>div
|
||||
display: inline-block
|
||||
|
||||
.header
|
||||
font-size: 22px
|
||||
font-weight: 300
|
||||
color: $tableTextSecondaryColor
|
||||
padding: 0 10px
|
||||
line-height: $studyListToolbarHeight
|
||||
|
||||
.studylistToolbar
|
||||
@ -35,20 +33,35 @@ $bodyCellHeight = 40px
|
||||
theme('color', '$uiSkyBlue')
|
||||
font-size: 40px
|
||||
font-weight: 100
|
||||
padding: 0 10px
|
||||
line-height: $studyListToolbarHeight
|
||||
|
||||
.theadBackground
|
||||
theme('background-color', '$uiGrayDarker')
|
||||
width: 100%
|
||||
height: 122px
|
||||
height: 121px
|
||||
position: absolute
|
||||
z-index: 1
|
||||
width: 100%
|
||||
|
||||
&:before, &:after
|
||||
content: ''
|
||||
display: block
|
||||
left: 0
|
||||
position: absolute
|
||||
width: 100%
|
||||
|
||||
&:before
|
||||
theme('background-color', '$uiGrayDarker')
|
||||
height: 100%
|
||||
top: 0
|
||||
z-index: 1
|
||||
|
||||
&:after
|
||||
theme('background-color', '$uiSkyBlue')
|
||||
bottom: -1px
|
||||
height: 1px
|
||||
z-index: 3
|
||||
|
||||
#studyListContainer
|
||||
background: black
|
||||
width: 100%
|
||||
padding: 0 $tablePadding
|
||||
padding: 0 $studyListPadding
|
||||
position: absolute
|
||||
z-index: 2
|
||||
|
||||
@ -64,7 +77,6 @@ $bodyCellHeight = 40px
|
||||
|
||||
table#tblStudyList
|
||||
thead
|
||||
theme('background-color', '$uiGrayDarker')
|
||||
white-space: nowrap
|
||||
|
||||
tr
|
||||
@ -144,15 +156,10 @@ $bodyCellHeight = 40px
|
||||
color: $tableTextPrimaryColor
|
||||
font-weight: 300
|
||||
border-top: 1px solid #436270
|
||||
border-bottom: 1px solid #436270
|
||||
white-space: nowrap
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:first-child
|
||||
padding-left: $tablePadding
|
||||
|
||||
&:last-child
|
||||
padding-right: $tablePadding
|
||||
|
||||
&:hover, &:active, &.active
|
||||
background-color: $tableHoverColor
|
||||
color: white
|
||||
@ -163,7 +170,6 @@ $bodyCellHeight = 40px
|
||||
border-bottom: 1px solid #436270
|
||||
background-color: $tableHoverColor
|
||||
|
||||
|
||||
@media only screen and (max-width: 1362px)
|
||||
$tablePadding = 5%
|
||||
|
||||
@ -238,4 +244,4 @@ $bodyCellHeight = 40px
|
||||
.worklistPagination
|
||||
.row
|
||||
margin-left: 0
|
||||
margin-right: 0
|
||||
margin-right: 0
|
||||
@ -24,4 +24,4 @@
|
||||
opacity: 0
|
||||
overflow: hidden
|
||||
position: absolute
|
||||
z-index: -1
|
||||
z-index: -1
|
||||
|
||||
@ -19,7 +19,7 @@ const currentServerChangeHandler = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
switchToTab('worklistTab');
|
||||
switchToTab('studylistTab');
|
||||
};
|
||||
|
||||
CurrentServer.find().observe({
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import './publications.js';
|
||||
import './servers.js';
|
||||
import './validateServerConfiguration.js';
|
||||
|
||||
import './lib';
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
Meteor.startup(function() {
|
||||
console.log('Adding Servers from JSON Configuration');
|
||||
@ -72,7 +73,7 @@ class ServersControl {
|
||||
}
|
||||
|
||||
static remove(serverId) {
|
||||
var query = {
|
||||
const query = {
|
||||
_id: serverId
|
||||
};
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
line-height: 18px
|
||||
|
||||
.caret-down
|
||||
theme('color', '$uiLightGray')
|
||||
theme('color', '$uiGrayLight')
|
||||
margin: 0 4px 4px 2px
|
||||
|
||||
ul.dropdown-menu
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.loadingTextDiv
|
||||
margin: 30px
|
||||
font-weight: 300
|
||||
padding: 30px
|
||||
text-align: center
|
||||
font-weight: 300
|
||||
@ -205,10 +205,6 @@ Template.thumbnailEntry.onCreated(() => {
|
||||
instance.isDragAndDrop = _.isUndefined(instance.data.viewportIndex);
|
||||
});
|
||||
|
||||
Template.thumbnailEntry.onRendered(() => {
|
||||
console.warn('thumbnailEntry onRendered');
|
||||
});
|
||||
|
||||
Template.thumbnailEntry.events({
|
||||
// Event handlers for drag and drop
|
||||
'touchstart .thumbnailEntry, mousedown .thumbnailEntry'(event, instance) {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<template name="standaloneViewer">
|
||||
<div class="topBar noselect">
|
||||
<div class="clearfix p-x-1 p-t-1">
|
||||
<div class="clearfix">
|
||||
<a target='_blank'
|
||||
class="brandSection pull-left"
|
||||
href="http://ohif.org">
|
||||
<svg class="logoImage">
|
||||
<use xlink:href="/packages/viewerbase/assets/icons.svg#icon-ohif-logo"></use>
|
||||
<use xlink:href="/packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"></use>
|
||||
</svg>
|
||||
<div class="logoText">
|
||||
Open Health Imaging Foundation
|
||||
@ -14,4 +14,4 @@
|
||||
</div>
|
||||
</div>
|
||||
{{> viewer }}
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@ -9,6 +9,8 @@ $expandedHeight = 160px
|
||||
|
||||
.topBar
|
||||
height: $topBarHeight
|
||||
overflow: hidden
|
||||
padding: 1rem $studyListPadding 0
|
||||
theme('color', '$textPrimaryColor')
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
transition(all 0.5s ease)
|
||||
@ -19,7 +21,7 @@ $expandedHeight = 160px
|
||||
text-decoration: none
|
||||
|
||||
.logoImage
|
||||
margin: 0 8px
|
||||
margin: 0 8px 0 0
|
||||
width: 30px
|
||||
|
||||
.logoText
|
||||
@ -50,17 +52,16 @@ $expandedHeight = 160px
|
||||
.brandSection
|
||||
height: 100%
|
||||
width: 80%
|
||||
padding-left: 50px
|
||||
line-height: $expandedHeight
|
||||
|
||||
.logoImage
|
||||
width: 50px
|
||||
margin: 0 20px
|
||||
margin: 0 20px 0 0
|
||||
|
||||
.logoText
|
||||
font-size: 30px
|
||||
|
||||
#worklistTabs
|
||||
#studylistTabs
|
||||
height: "calc(100% - %s)" % $topBarHeight
|
||||
|
||||
.tab-pane
|
||||
|
||||
Loading…
Reference in New Issue
Block a user