Cleaned up dialog styles (OHIF-49) and duplicate calls to Worklist Search (credit to @mdg583)

This commit is contained in:
Erik Ziegler 2016-08-03 23:17:42 +02:00
parent 7d4c76ddb0
commit 1a264f81e5
32 changed files with 240 additions and 197 deletions

View File

@ -7,7 +7,7 @@ $lesionsSidebarMenuWidth = 450px
flex: 1
flex-flow: row nowrap
align-items: stretch
height: 'calc(100% - %s)' %toolbarHeight;
height: 'calc(100% - %s)' % $toolbarHeight;
width: 100%
.sidebarMenu

View File

@ -8,21 +8,6 @@ Template.ohifViewer.onCreated(() => {
ViewerData = Session.get('ViewerData') || {};
});
Template.ohifViewer.onRendered(() => {
const templateData = Template.currentData();
if (templateData && templateData.studyInstanceUid) {
const studyInstanceUid = templateData.studyInstanceUid;
openNewTab(studyInstanceUid, studyInstanceUid);
} else {
// If there is a tab set as active in the Session,
// switch to that now.
const contentId = Session.get('activeContentId');
// TODO: Fix this it seems to be forcing two switches
switchToTab(contentId);
}
});
Template.ohifViewer.events({
'click .js-toggle-studyList'() {
const contentId = Session.get('activeContentId');
@ -52,6 +37,7 @@ Template.ohifViewer.helpers({
return 'Study list';
}
},
onStudyList() {
return (Session.get('activeContentId') === 'worklistTab');
}

View File

@ -3,6 +3,11 @@
<div class="viewerDialogs">
{{> cineDialog}}
{{> layoutChooser }}
<!-- Hanging Protocol dialogs -->
{{ >ruleEntryDialog }}
{{ >settingEntryDialog }}
{{ >textEntryDialog }}
</div>
<div id="viewer">
{{> toolbarSection (clone this)}}

View File

@ -53,4 +53,4 @@ placeholder-color(c)
&::-moz-placeholder
color: c
&:-ms-input-placeholder
color: c
color: c

View File

@ -14,13 +14,13 @@ $hoverColor = #ffffff
$activeColor = #00a4d9
$uiBorderColor = #436270
$uiBorderColorDark = #3C5D80
$uiBorderColorActive = #3C8074
$uiBorderColorActive = #00a4d9
$primaryBackgroundColor = #000000
$boxBackgroundColor = #344a61
$boxBackgroundColorDark = #22374D
// Text Colors
$textColorActive = #89bae5
$textColorActive = black //#89bae5
$textPrimaryColor = #ffffff
$textSecondaryColor = #6a8fb1

View File

@ -1,2 +1,2 @@
@import "./theme-tigerlilly.styl"
//@import "./theme-tide.styl"
//@import "./theme-tigerlilly.styl"
@import "./theme-tide.styl"

View File

@ -1,7 +1,4 @@
<template name="protocolEditor">
{{ >ruleEntryDialog }}
{{ >settingEntryDialog }}
{{ >textEntryDialog }}
<div id='protocolEditor'>
<div class="row">
<div class="navigationButtons col-xs-12">

View File

@ -8,7 +8,7 @@ $height = 20px
padding: 10px
position: absolute
top: 0
background: $primaryBackgroundCOlor
background: $primaryBackgroundColor
.navigationButtons
ul

View File

@ -211,13 +211,16 @@ Template.ruleEntryDialog.onCreated(function() {
Template.ruleEntryDialog.onRendered(function() {
// Initialize the Comparators Select2 box
var template = this;
var template = Template.instance();
template.$('.comparators').select2();
// Get the default Comparator from the Select2 box and use it to
// initialize the comparatorId ReactiveVar
var comparatorId = template.$('.comparators').val();
template.comparatorId.set(comparatorId);
const dialog = template.$('.ruleEntryDialog');
dialog.draggable();
});
Template.ruleEntryDialog.helpers({

View File

@ -1,3 +1,5 @@
@import "{design}/app.styl"
.ruleEntryDialog
display: none
position: absolute
@ -6,15 +8,19 @@
left: 0
right: 0
z-index: 100
width: 50%
max-width: 400px
width: 350px
height: 230px
margin: auto
border-radius: 5px
padding: 10px 20px 10px 20px
padding: 10px
background-color: rgba(255,255,255,1)
outline: none
opacity: 0.95
border-radius: 8px
border: 1px solid $uiBorderColor
background: $uiGrayDarkest
color: $textSecondaryColor
.dialogContent
text-align: center
margin-bottom: 10px
@ -33,4 +39,9 @@
input.currentValue
width: 95%
text-align: center
text-align: center
padding: 4px
color: black
height: 30px
border-radius: 2px
border: 0

View File

@ -113,6 +113,12 @@ Template.settingEntryDialog.onCreated(function() {
template.setting = new ReactiveVar();
});
Template.settingEntryDialog.onRendered(function() {
const template = this;
const dialog = template.$('.settingEntryDialog');
dialog.draggable();
});
Template.settingEntryDialog.events({
/**
* Save a setting that is being edited

View File

@ -1,3 +1,5 @@
@import "{design}/app.styl"
.settingEntryDialog
display: none
position: absolute
@ -6,15 +8,18 @@
left: 0
right: 0
z-index: 100
width: 50%
max-width: 400px
height: 230px
width: 300px
height: 200px
margin: auto
border-radius: 5px
padding: 10px 20px 10px 20px
background-color: rgba(255,255,255,1)
padding: 10px
outline: none
opacity: 0.95
border-radius: 8px
border: 1px solid $uiBorderColor
background: $uiGrayDarkest
color: $textSecondaryColor
.dialogContent
text-align: center
margin-bottom: 10px
@ -33,4 +38,9 @@
input.currentValue
width: 95%
text-align: center
text-align: center
padding: 4px
color: black
height: 30px
border-radius: 2px
border: 0

View File

@ -46,6 +46,7 @@
.addStage
margin: 10px 0
text-align: center
color: $defaultColor
#addStage
transition(all 0.1s ease)

View File

@ -57,6 +57,12 @@ openTextEntryDialog = function(title, instructions, currentValue, doneCallback)
});
};
Template.textEntryDialog.onRendered(() => {
const instance = Template.instance();
const dialog = instance.$('.settingEntryDialog');
dialog.draggable();
});
Template.textEntryDialog.events({
/**
* Save the user-specified text

View File

@ -1,3 +1,5 @@
@import "{design}/app.styl"
.textEntryDialog
display: none
position: absolute
@ -6,15 +8,18 @@
left: 0
right: 0
z-index: 100
width: 50%
max-width: 400px
width: 300px
height: 170px
margin: auto
border-radius: 5px
padding: 10px 20px 10px 20px
background-color: rgba(255,255,255,1)
padding: 10px
outline: none
opacity: 0.95
border-radius: 8px
border: 1px solid $uiBorderColor
background: $uiGrayDarkest
color: $textSecondaryColor
.dialogContent
margin-bottom: 10px
@ -26,4 +31,9 @@
input.currentValue
width: 95%
text-align: left
text-align: left
padding: 4px
color: black
height: 30px
border-radius: 2px
border: 0

View File

@ -5,7 +5,7 @@ Package.describe({
});
Package.onUse(function(api) {
api.versionsFrom('1.3.5.1');
api.versionsFrom('1.4');
api.use('ecmascript');
api.use('standard-app-packages');

View File

@ -1,24 +1,11 @@
// Define the ViewerData global object
// If there is currently any Session data for this object,
// use this to repopulate the variable
ViewerData = Session.get('ViewerData') || {};
const worklistContentId = 'worklistTab';
const viewerContentId = 'viewerTab';
Template.lesionTracker.onRendered(() => {
const templateData = Template.currentData();
if (templateData && templateData.studyInstanceUid) {
const studyInstanceUid = templateData.studyInstanceUid;
openNewTab(studyInstanceUid, studyInstanceUid);
} else {
// If there is a tab set as active in the Session,
// switch to that now.
const contentId = Session.get('activeContentId');
// TODO: Fix this it seems to be forcing two switches
switchToTab(contentId);
}
// Define the ViewerData global object
// If there is currently any Session data for this object,
// use this to repopulate the variable
Template.lesionTracker.onCreated(() => {
ViewerData = Session.get('ViewerData') || {};
});
Template.lesionTracker.events({
@ -33,8 +20,6 @@ Template.lesionTracker.events({
}
});
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');
Template.lesionTracker.helpers({
studyListToggleText() {
const contentId = Session.get('activeContentId');
@ -52,7 +37,10 @@ Template.lesionTracker.helpers({
return 'Study list';
}
},
onStudyList() {
return (Session.get('activeContentId') === 'worklistTab');
}
});
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');

View File

@ -135,6 +135,7 @@ function exportSelectedStudies() {
* Loads multiple unassociated studies in the Viewer
*/
function viewStudies() {
console.log('viewStudies');
var selectedStudies = WorklistSelectedStudies.find({}, {
sort: {
studyDate: 1

View File

@ -6,6 +6,7 @@
* @param title The title to be used for the tab heading
*/
openNewTabWithTimepoint = function(timepointId, title) {
console.log('openNewTabWithTimepoint');
var contentId = 'viewerTab';
var timepoint = Timepoints.findOne({

View File

@ -68,5 +68,6 @@ function open(studyInstanceUid, title) {
};
// Switch to the new tab
console.log('open');
switchToTab(contentid);
}

View File

@ -5,7 +5,7 @@ Package.describe({
});
Package.onUse(function(api) {
api.versionsFrom('1.3.5.1');
api.versionsFrom('1.4');
api.use('ecmascript');
api.use('standard-app-packages');

View File

@ -11,14 +11,14 @@ $borderColor = rgba(77, 99, 110, 0.81)
bottom: 3px
right: 3px
overflow: hidden
overflow: hidden
padding: 10px
width: 300px
height: 175px
opacity: 0.95
border-radius: 8px
border: 1px solid $borderColor;
border: 1px solid $uiBorderColor
background: $uiGrayDarkest
color: $textSecondaryColor

View File

@ -25,16 +25,16 @@ function configureTools() {
cornerstoneTools.panMultiTouch.setConfiguration(multiTouchPanConfig);
// Set the text box background color
cornerstoneTools.textStyle.setBackgroundColor('black');
cornerstoneTools.textStyle.setBackgroundColor('rgba(0, 0, 0, 0.95)');
// Set the tool width
cornerstoneTools.toolStyle.setToolWidth(2);
// Set color for inactive tools
cornerstoneTools.toolColors.setToolColor('rgb(255, 255, 0)');
cornerstoneTools.toolColors.setToolColor('#ff00ff'); //rgb(255, 255, 0)');
// Set color for active tools
cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
cornerstoneTools.toolColors.setActiveColor('#00ffff'); //rgb(0, 255, 0)'
}
toolManager = {

View File

@ -6,6 +6,8 @@ Template.tabTitle.events({
* @param e The click event used to close the tab
*/
'click .close': function(e) {
console.log('click .close');
// Identify the tab title DOM node
var tab = $(e.currentTarget).parents('a[data-toggle="tab"]').eq(0);

View File

@ -30,10 +30,11 @@ Template.worklist.onRendered(() => {
} else {
// If there is a tab set as active in the Session,
// switch to that now.
console.log('worklist onRendered');
const contentId = Session.get('activeContentId');
// TODO: FIx this it seems to be forcing two switches
switchToTab(contentId);
if (contentId !== 'worklistTab') {
switchToTab(contentId);
}
}
Meteor.subscribe('hangingprotocols');

View File

@ -15,31 +15,29 @@
<div id="studyListContainer">
<table id="tblStudyList" class="worklistResult table noselect">
<thead>
<tr>
<th>
<div id="_patientName" class="sortingCell">
<span>Patient Name</span>
<i class="{{sortingColumnsIcons.patientName}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
id="patientName"
placeholder="Patient Name">
</th>
<th>
<div id="_patientId" class="sortingCell">
<span>MRN</span>
<i class="{{sortingColumnsIcons.patientId}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
id="patientId"
placeholder="MRN">
</th>
{{#unless isTouchDevice}}
<th>
<div id="_accessionNumber" class="sortingCell">
<tr>
<th class="patientName">
<div id="_patientName" class="sortingCell">
<span>Patient Name</span>
<i class="{{sortingColumnsIcons.patientName}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
id="patientName"
placeholder="Patient Name">
</th>
<th class="patientId">
<div id="_patientId" class="sortingCell">
<span>MRN</span>
<i class="{{sortingColumnsIcons.patientId}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
id="patientId"
placeholder="MRN">
</th>
<th class="accessionNumber">
<div id="_accessionNumber" class="sortingCell ">
<span>Accession #</span>
<i class="{{sortingColumnsIcons.accessionNumber}}">&nbsp;</i>
</div>
@ -48,22 +46,18 @@
id="accessionNumber"
placeholder="Accession #">
</th>
{{/unless}}
<th>
<div id="_studyDate" class="sortingCell">
<span>Study Date</span>
<i class="{{sortingColumnsIcons.studyDate}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
name="daterange"
id="studyDate"
placeholder="Study Date">
</th>
{{#unless isTouchDevice}}
<th>
<th class="studyDate">
<div id="_studyDate" class="sortingCell">
<span>Study Date</span>
<i class="{{sortingColumnsIcons.studyDate}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
name="daterange"
id="studyDate"
placeholder="Study Date">
</th>
<th class="modalities">
<div id="_modalities" class="sortingCell">
<span>Modality</span>
<i class="{{sortingColumnsIcons.modalities}}">&nbsp;</i>
@ -73,28 +67,24 @@
id="modality"
placeholder="Modality">
</th>
{{/unless}}
<th>
<div id="_studyDescription" class="sortingCell">
<span>Study Description</span>
<i class="{{sortingColumnsIcons.studyDescription}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
id="studyDescription"
placeholder="Study Description">
</th>
{{#unless isTouchDevice}}
<th>
<div id="_numberOfStudyRelatedInstances" class="sortingCell">
<span># Images</span>
<i class="{{sortingColumnsIcons.numberOfStudyRelatedInstances}}">&nbsp;</i>
</div>
<input type="text" class="form-control worklist-search invisible"/>
</th>
{{/unless}}
</tr>
<th class="studyDescription">
<div id="_studyDescription" class="sortingCell">
<span>Study Description</span>
<i class="{{sortingColumnsIcons.studyDescription}}">&nbsp;</i>
</div>
<input type="text"
class="form-control worklist-search"
id="studyDescription"
placeholder="Study Description">
</th>
<th class="numberOfStudyRelatedInstances">
<div id="_numberOfStudyRelatedInstances" class="sortingCell">
<span># Images</span>
<i class="{{sortingColumnsIcons.numberOfStudyRelatedInstances}}">&nbsp;</i>
</div>
<input type="text" class="form-control worklist-search invisible"/>
</th>
</tr>
</thead>
<tbody id="studyListData">
{{#each studies}}
@ -102,12 +92,12 @@
{{/each}}
</tbody>
</table>
{{#if showLoadingText}}
{{#if session "showLoadingText"}}
{{>loadingText}}
{{/if}}
{{#if showNotFoundMessage}}
{{#unless numberOfStudies}}
<div class="notFound">No matching results</div>
{{/if}}
{{/unless}}
</div>
</template>

View File

@ -1,7 +1,4 @@
Session.setDefault('searchResults', {
showLoadingText: true,
showNotFoundMessage: false
});
Session.setDefault('showLoadingText', true);
Template.worklistResult.helpers({
/**
@ -28,14 +25,6 @@ Template.worklistResult.helpers({
return WorklistStudies.find().count();
},
showLoadingText() {
return Session.get('searchResults').showLoadingText;
},
showNotFoundMessage() {
return Session.get('searchResults').showNotFoundMessage;
},
sortingColumnsIcons() {
const instance = Template.instance();
@ -116,18 +105,19 @@ function convertStringToStudyDate(dateStr) {
* Inserts the identified studies into the WorklistStudies Collection
*/
function search() {
console.log('search()');
// Show loading message
let searchResults = Session.get('searchResults');
searchResults.showLoadingText = true;
searchResults.showNotFoundMessage = false;
Session.set('searchResults', searchResults);
Session.set('showLoadingText', true);
// Create the filters to be used for the Worklist Search
filter = {
patientName: getFilter($('input#patientName').val()),
patientId: getFilter($('input#patientId').val()),
accessionNumber: getFilter($('input#accessionNumber').val()),
studyDescription: getFilter($('input#studyDescription').val())
studyDescription: getFilter($('input#studyDescription').val()),
studyDateFrom: studyDateFrom,
studyDateTo: studyDateTo
};
// Make sure that modality has a reasonable value, since it is occasionally
@ -138,14 +128,14 @@ function search() {
WorklistStudies.remove({});
Meteor.call('WorklistSearch', filter, (error, studies) => {
console.log('WorklistSearch');
if (error) {
log.warn(error);
return;
}
// Hide loading text
searchResults.showLoadingText = false;
Session.set('searchResults', searchResults);
Session.set('showLoadingText', false);
if (!studies) {
return;
@ -165,13 +155,6 @@ function search() {
WorklistStudies.insert(study);
}
});
if (WorklistStudies.find().count() === 0) {
// Show studyNotFound text
searchResults.showNotFoundMessage = true;
Session.set('searchResults', searchResults);
}
});
}
@ -180,9 +163,6 @@ Template.worklistResult.onCreated(() => {
instance.sortOption = new ReactiveVar();
instance.sortingColumns = new ReactiveDict();
// Retrieve all studies
search();
// Set sortOption
const sortOptionSession = Session.get('sortOption');
if (sortOptionSession) {
@ -217,6 +197,9 @@ Template.worklistResult.onRendered(() => {
'Last 30 Days': [moment().subtract(29, 'days'), moment()]
}
});
// Retrieve all studies
search();
});
function resetSortingColumns(instance, sortingColumn) {

View File

@ -50,6 +50,7 @@ $bodyCellHeight = 40px
width: 100%
padding: 0 $tablePadding
position: absolute
overflow: hidden
z-index: 2
.loadingTextDiv
@ -117,6 +118,7 @@ $bodyCellHeight = 40px
box-sizing: border-box
transition(all 0.15s ease)
placeholder-color($inputPlaceholderColor)
&.invisible
visibility: hidden
@ -124,20 +126,6 @@ $bodyCellHeight = 40px
&:active, &:hover
background-color: $inputBackgroundColor
&::-webkit-input-placeholder /* WebKit, Blink, Edge */
color: $inputPlaceholderColor
&:-moz-placeholder /* Mozilla Firefox 4 to 18 */
color: $inputPlaceholderColor
opacity: 1
&::-moz-placeholder /* Mozilla Firefox 19+ */
color: $inputPlaceholderColor
opacity: 1
&:-ms-input-placeholder /* Internet Explorer 10-11 */
color: $inputPlaceholderColor
::-webkit-datetime-edit-year-field:not([aria-valuenow]),
::-webkit-datetime-edit-month-field:not([aria-valuenow]),
::-webkit-datetime-edit-day-field:not([aria-valuenow])
@ -176,3 +164,29 @@ $bodyCellHeight = 40px
border-top: 1px solid #436270
border-bottom: 1px solid #436270
background-color: $hoverColor
@media only screen and (max-width: 1000px)
$tablePaddingMediumScreen = 10px
#studyListContainer
padding: 0
table#tblStudyList
thead > tr > th
&:first-child
padding-left: $tablePaddingMediumScreen
&:last-child
padding-right: $tablePaddingMediumScreen
tbody > tr > td
&:first-child
padding-left: $tablePaddingMediumScreen
&:last-child
padding-right: $tablePaddingMediumScreen
th.accessionNumber, td.accessionNumber,
th.modalities, td.modalities,
th.numberOfStudyRelatedInstances, td.numberOfStudyRelatedInstances
display: none

View File

@ -1,31 +1,25 @@
<template name="worklistStudy">
<tr class="worklistStudy noselect">
<td>
<td class="patientName">
{{formatPN patientName}}
</td>
<td>
<td class="patientId">
{{patientId}}
</td>
{{#unless isTouchDevice}}
<td>
<td class="accessionNumber">
{{accessionNumber}}
</td>
{{/unless}}
<td>
<td class="studyDate">
{{formatDA studyDate}}
</td>
{{#unless isTouchDevice}}
<td>
<td class="modalities">
{{modalities}}
</td>
{{/unless}}
<td>
<td class="studyDescription">
{{studyDescription}}
</td>
{{#unless isTouchDevice}}
<td>
<td class="numberOfStudyRelatedInstances">
{{numberOfStudyRelatedInstances}}
</td>
{{/unless}}
</tr>
</template>

View File

@ -6,6 +6,8 @@
* @param title The title to be used for the tab heading
*/
openNewTab = function(studyInstanceUid, title) {
console.log('openNewTab');
// Generate a unique ID to represent this tab
// We can't just use the Mongo entry ID because
// then it will change after hot-reloading.

View File

@ -22,6 +22,7 @@ Package.onUse(function (api) {
api.use('gilbertwat:bootstrap3-daterangepicker');
// Our custom packages
api.use('ohif:core');
api.use('design');
api.use('dicomweb');
api.use('dimseservice');

View File

@ -1,3 +1,21 @@
/**
* Creates a QIDO date string for a date range query
* Assumes the year is positive, at most 4 digits long.
*
* @param date The Date object to be formatted
* @returns {string} The formatted date string
*/
function dateToString(date) {
if(!date) return "";
var year = date.getFullYear().toString();
var month = (date.getMonth() + 1).toString();
var day = date.getDate().toString();
year = "0".repeat(4-year.length).concat(year);
month= "0".repeat(2-month.length).concat(month);
day = "0".repeat(2-day.length).concat(day);
return "".concat(year,month,day);
}
/**
* Produces a QIDO URL given server details and a set of specified search filter
* items
@ -19,8 +37,15 @@ function filterToQIDOURL(server, filter) {
AccessionNumber: filter.accessionNumber,
StudyDescription: filter.studyDescription,
limit: filter.limit || 20,
includefield: server.qidoSupportsIncludeField ? 'all' : commaSeparatedFields
includefield: server.qidoSupportsIncludeField ? commaSeparatedFields : 'all'
};
// build the StudyDate range parameter
if (filter.studyDateFrom || filter.sutydDateTo) {
var date = "".concat(dateToString(new Date(filter.studyDateFrom)), "-", dateToString(new Date(filter.studyDateTo)));
parameters.StudyDate = date;
}
return server.qidoRoot + '/studies?' + encodeQueryData(parameters);
}
@ -33,6 +58,10 @@ function filterToQIDOURL(server, filter) {
function resultDataToStudies(resultData) {
var studies = [];
if (!resultData || !resultData.length) {
return;
}
resultData.forEach(function(study) {
studies.push({
studyInstanceUid: DICOMWeb.getString(study['0020000D']),
@ -55,6 +84,7 @@ function resultDataToStudies(resultData) {
modalities: DICOMWeb.getString(DICOMWeb.getModalities(study['00080060'], study['00080061']))
});
});
return studies;
}