AWV-3: Merging changes from upstream
This commit is contained in:
commit
176b503c5a
@ -13,3 +13,4 @@ notices-for-facebook-graph-api-2
|
||||
1.3.0-split-minifiers-package
|
||||
1.3.5-remove-old-dev-bundle-link
|
||||
1.4.0-remove-old-dev-bundle-link
|
||||
1.4.1-add-shell-server-package
|
||||
|
||||
@ -4,18 +4,18 @@
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
npm-bcrypt@0.8.7
|
||||
npm-bcrypt@0.9.1
|
||||
|
||||
meteor-base@1.0.4 # Packages every Meteor app needs to have
|
||||
mobile-experience@1.0.4 # Packages for a great mobile UX
|
||||
mongo@1.1.10 # The database Meteor supports right now
|
||||
mongo@1.1.12 # The database Meteor supports right now
|
||||
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
|
||||
session@1.1.6 # Client-side reactive dictionary for your app
|
||||
jquery@1.11.9 # Helpful client-side library
|
||||
jquery@1.11.9 # Helpful client-side library
|
||||
tracker@1.1.0 # Meteor's client-side reactive programming library
|
||||
|
||||
es5-shim@4.6.13 # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript@0.5.7 # Enable ECMAScript2015+ syntax in app code
|
||||
es5-shim@4.6.14 # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript@0.5.8 # Enable ECMAScript2015+ syntax in app code
|
||||
|
||||
clinical:router
|
||||
clinical:extended-api
|
||||
@ -26,6 +26,8 @@ clinical:fonts
|
||||
clinical:hipaa-audit-log
|
||||
clinical:hipaa-logger
|
||||
|
||||
aldeed:simple-schema # Third party package to deal with schemas
|
||||
|
||||
design
|
||||
ohif:core
|
||||
|
||||
@ -34,15 +36,15 @@ cornerstone
|
||||
worklist
|
||||
viewerbase
|
||||
dicomweb
|
||||
accounts-base@1.2.9
|
||||
accounts-password@1.2.12
|
||||
accounts-base@1.2.11
|
||||
accounts-password@1.3.0
|
||||
|
||||
ian:accounts-ui-bootstrap-3
|
||||
twbs:bootstrap
|
||||
http@1.2.8
|
||||
http@1.2.9
|
||||
arsnebula:reactive-promise
|
||||
promise@0.8.3
|
||||
stylus@2.513.4
|
||||
promise@0.8.4
|
||||
stylus@2.513.5
|
||||
fortawesome:fontawesome
|
||||
random@1.0.10
|
||||
reactive-var@1.0.10
|
||||
@ -56,11 +58,13 @@ check@1.2.3
|
||||
aldeed:template-extension@4.0.0
|
||||
zuuk:stale-session
|
||||
gilbertwat:bootstrap3-daterangepicker
|
||||
email@1.1.16
|
||||
email@1.1.17
|
||||
peppelg:bootstrap-3-modal
|
||||
simple:reactive-method
|
||||
hangingprotocols
|
||||
fastclick@1.0.12
|
||||
standard-minifier-css@1.1.8
|
||||
standard-minifier-js@1.1.8
|
||||
standard-minifier-css@1.2.0
|
||||
standard-minifier-js@1.2.0
|
||||
johdirr:meteor-git-rev
|
||||
u2622:persistent-session
|
||||
shell-server
|
||||
|
||||
@ -1 +1 @@
|
||||
METEOR@1.4.0.1
|
||||
METEOR@1.4.1.1
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
accounts-base@1.2.9
|
||||
accounts-password@1.2.12
|
||||
accounts-base@1.2.11
|
||||
accounts-password@1.3.0
|
||||
aldeed:simple-schema@1.5.3
|
||||
aldeed:template-extension@4.0.0
|
||||
allow-deny@1.0.5
|
||||
amplify@1.0.0
|
||||
anti:gagarin@0.4.11
|
||||
anti:i18n@0.4.3
|
||||
arsnebula:reactive-promise@0.9.1
|
||||
autoupdate@1.3.11
|
||||
babel-compiler@6.9.0
|
||||
babel-runtime@0.1.10
|
||||
babel-compiler@6.9.1
|
||||
babel-runtime@0.1.11
|
||||
base64@1.0.9
|
||||
binary-heap@1.0.9
|
||||
blaze@2.1.8
|
||||
blaze-html-templates@1.0.4
|
||||
blaze-tools@1.0.9
|
||||
boilerplate-generator@1.0.9
|
||||
caching-compiler@1.1.6
|
||||
caching-compiler@1.1.7
|
||||
caching-html-compiler@1.0.6
|
||||
callback-hook@1.0.9
|
||||
check@1.2.3
|
||||
@ -31,23 +32,23 @@ clinical:router-location@2.1.0
|
||||
clinical:router-middleware-stack@2.1.2
|
||||
clinical:router-url@2.1.0
|
||||
clinical:theming@0.4.10
|
||||
coffeescript@1.2.3
|
||||
coffeescript@1.2.4_1
|
||||
cornerstone@0.0.1
|
||||
ddp@1.2.5
|
||||
ddp-client@1.3.0
|
||||
ddp-client@1.3.1
|
||||
ddp-common@1.2.6
|
||||
ddp-rate-limiter@1.0.5
|
||||
ddp-server@1.3.9
|
||||
ddp-server@1.3.10
|
||||
deps@1.0.12
|
||||
design@0.0.1
|
||||
dicomweb@0.0.1
|
||||
diff-sequence@1.0.6
|
||||
dimseservice@0.0.1
|
||||
ecmascript@0.5.7
|
||||
ecmascript-runtime@0.3.12
|
||||
ecmascript@0.5.8
|
||||
ecmascript-runtime@0.3.14
|
||||
ejson@1.0.12
|
||||
email@1.1.16
|
||||
es5-shim@4.6.13
|
||||
email@1.1.17
|
||||
es5-shim@4.6.14
|
||||
fastclick@1.0.12
|
||||
fortawesome:fontawesome@4.5.0
|
||||
geojson-utils@1.0.9
|
||||
@ -57,7 +58,7 @@ hangingprotocols@0.0.1
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.10
|
||||
htmljs@1.0.10
|
||||
http@1.2.8
|
||||
http@1.2.9
|
||||
ian:accounts-ui-bootstrap-3@1.2.89
|
||||
id-map@1.0.8
|
||||
insecure@1.0.7
|
||||
@ -71,25 +72,25 @@ launch-screen@1.0.12
|
||||
lesiontracker@0.0.1
|
||||
livedata@1.0.18
|
||||
localstorage@1.0.11
|
||||
logging@1.1.14
|
||||
logging@1.1.15
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.2.16
|
||||
meteor@1.2.17
|
||||
meteor-base@1.0.4
|
||||
meteor-platform@1.2.6
|
||||
minifier-css@1.2.13
|
||||
minifier-js@1.2.13
|
||||
minifier-css@1.2.14
|
||||
minifier-js@1.2.14
|
||||
minimongo@1.0.17
|
||||
mobile-experience@1.0.4
|
||||
mobile-status-bar@1.0.12
|
||||
modules@0.7.5
|
||||
modules-runtime@0.7.5
|
||||
modules@0.7.6
|
||||
modules-runtime@0.7.6
|
||||
momentjs:moment@2.14.4
|
||||
mongo@1.1.10
|
||||
mongo@1.1.12
|
||||
mongo-id@1.0.5
|
||||
mrt:moment@2.8.1
|
||||
natestrauser:select2@4.0.2
|
||||
npm-bcrypt@0.8.7
|
||||
npm-mongo@1.5.45
|
||||
natestrauser:select2@4.0.3
|
||||
npm-bcrypt@0.9.1
|
||||
npm-mongo@1.5.49
|
||||
observe-sequence@1.0.12
|
||||
ohif:core@0.0.1
|
||||
ordered-dict@1.0.8
|
||||
@ -97,7 +98,7 @@ orthanc-remote@0.0.1
|
||||
peppelg:bootstrap-3-modal@1.0.4
|
||||
practicalmeteor:chai@2.1.0_1
|
||||
practicalmeteor:loglevel@1.2.0_2
|
||||
promise@0.8.3
|
||||
promise@0.8.4
|
||||
random@1.0.10
|
||||
rate-limit@1.0.5
|
||||
reactive-dict@1.1.8
|
||||
@ -109,27 +110,30 @@ rwatts:uuid@0.1.0
|
||||
service-configuration@1.0.10
|
||||
session@1.1.6
|
||||
sha@1.0.8
|
||||
shell-server@0.2.1
|
||||
silentcicero:jszip@0.0.4
|
||||
simple:reactive-method@1.0.2
|
||||
spacebars@1.0.12
|
||||
spacebars-compiler@1.0.12
|
||||
srp@1.0.9
|
||||
standard-app-packages@1.0.9
|
||||
standard-minifier-css@1.1.8
|
||||
standard-minifier-js@1.1.8
|
||||
stylus@2.513.4
|
||||
templating@1.2.13
|
||||
standard-minifier-css@1.2.0
|
||||
standard-minifier-js@1.2.0
|
||||
stylus@2.513.5
|
||||
templating@1.2.14
|
||||
templating-tools@1.0.4
|
||||
tracker@1.1.0
|
||||
twbs:bootstrap@3.3.6
|
||||
typ:accounts-ldap@1.0.1
|
||||
typ:ldapjs@0.7.3
|
||||
u2622:persistent-session@0.4.4
|
||||
ui@1.0.11
|
||||
underscore@1.0.9
|
||||
url@1.0.10
|
||||
validatejs@0.0.1
|
||||
viewerbase@0.0.1
|
||||
webapp@1.3.10
|
||||
wadoproxy@0.0.1
|
||||
webapp@1.3.11
|
||||
webapp-hashing@1.0.9
|
||||
worklist@0.0.1
|
||||
zuuk:stale-session@1.0.8
|
||||
|
||||
@ -16,7 +16,8 @@ var data = {
|
||||
'optionsModal',
|
||||
'serverInformationModal',
|
||||
'confirmRemoveTimepointAssociation',
|
||||
'lastLoginModal'
|
||||
'lastLoginModal',
|
||||
'viewSeriesDetailsModal'
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@ -13,3 +13,4 @@ notices-for-facebook-graph-api-2
|
||||
1.3.0-split-minifiers-package
|
||||
1.3.5-remove-old-dev-bundle-link
|
||||
1.4.0-remove-old-dev-bundle-link
|
||||
1.4.1-add-shell-server-package
|
||||
|
||||
@ -5,20 +5,20 @@
|
||||
# but you can also edit it by hand.
|
||||
|
||||
twbs:bootstrap
|
||||
http@1.2.8
|
||||
http@1.2.9
|
||||
arsnebula:reactive-promise
|
||||
promise@0.8.3
|
||||
stylus@2.513.4
|
||||
promise@0.8.4
|
||||
stylus@2.513.5
|
||||
fortawesome:fontawesome
|
||||
mrt:moment
|
||||
meteor-base@1.0.4
|
||||
mobile-experience@1.0.4
|
||||
mongo@1.1.10
|
||||
mongo@1.1.12
|
||||
blaze-html-templates@1.0.4
|
||||
session@1.1.6
|
||||
jquery@1.11.9
|
||||
tracker@1.1.0
|
||||
logging@1.1.14
|
||||
logging@1.1.15
|
||||
reload@1.1.10
|
||||
random@1.0.10
|
||||
ejson@1.0.12
|
||||
@ -26,9 +26,10 @@ spacebars@1.0.12
|
||||
check@1.2.3
|
||||
cornerstone
|
||||
dicomweb
|
||||
aldeed:simple-schema # Third party package to deal with schemas
|
||||
design
|
||||
ohif:core
|
||||
ecmascript@0.5.7
|
||||
ecmascript@0.5.8
|
||||
viewerbase
|
||||
worklist
|
||||
reactive-var@1.0.10
|
||||
@ -37,7 +38,10 @@ hangingprotocols
|
||||
reactive-dict@1.1.8
|
||||
clinical:router
|
||||
fastclick@1.0.12
|
||||
standard-minifier-css@1.1.8
|
||||
standard-minifier-js@1.1.8
|
||||
aldeed:simple-schema
|
||||
standard-minifier-css@1.2.0
|
||||
standard-minifier-js@1.2.0
|
||||
johdirr:meteor-git-rev
|
||||
wadoproxy
|
||||
aldeed:template-extension
|
||||
peppelg:bootstrap-3-modal
|
||||
shell-server
|
||||
|
||||
@ -1 +1 @@
|
||||
METEOR@1.4.0.1
|
||||
METEOR@1.4.1.1
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
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.11
|
||||
babel-compiler@6.9.0
|
||||
babel-runtime@0.1.10
|
||||
babel-compiler@6.9.1
|
||||
babel-runtime@0.1.11
|
||||
base64@1.0.9
|
||||
binary-heap@1.0.9
|
||||
blaze@2.1.8
|
||||
blaze-html-templates@1.0.4
|
||||
blaze-tools@1.0.9
|
||||
boilerplate-generator@1.0.9
|
||||
caching-compiler@1.1.6
|
||||
caching-compiler@1.1.7
|
||||
caching-html-compiler@1.0.6
|
||||
callback-hook@1.0.9
|
||||
check@1.2.3
|
||||
@ -18,19 +19,19 @@ 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.2.3
|
||||
coffeescript@1.2.4_1
|
||||
cornerstone@0.0.1
|
||||
ddp@1.2.5
|
||||
ddp-client@1.3.0
|
||||
ddp-client@1.3.1
|
||||
ddp-common@1.2.6
|
||||
ddp-server@1.3.9
|
||||
ddp-server@1.3.10
|
||||
deps@1.0.12
|
||||
design@0.0.1
|
||||
dicomweb@0.0.1
|
||||
diff-sequence@1.0.6
|
||||
dimseservice@0.0.1
|
||||
ecmascript@0.5.7
|
||||
ecmascript-runtime@0.3.12
|
||||
ecmascript@0.5.8
|
||||
ecmascript-runtime@0.3.14
|
||||
ejson@1.0.12
|
||||
fastclick@1.0.12
|
||||
fortawesome:fontawesome@4.5.0
|
||||
@ -40,7 +41,7 @@ hangingprotocols@0.0.1
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.10
|
||||
htmljs@1.0.10
|
||||
http@1.2.8
|
||||
http@1.2.9
|
||||
id-map@1.0.8
|
||||
iron:controller@1.0.12
|
||||
iron:core@1.0.11
|
||||
@ -50,31 +51,32 @@ johdirr:meteor-git-rev@0.0.4
|
||||
jquery@1.11.9
|
||||
launch-screen@1.0.12
|
||||
livedata@1.0.18
|
||||
logging@1.1.14
|
||||
mdg:validation-error@0.2.0
|
||||
meteor@1.2.16
|
||||
logging@1.1.15
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.2.17
|
||||
meteor-base@1.0.4
|
||||
meteor-platform@1.2.6
|
||||
minifier-css@1.2.13
|
||||
minifier-js@1.2.13
|
||||
minifier-css@1.2.14
|
||||
minifier-js@1.2.14
|
||||
minimongo@1.0.17
|
||||
mobile-experience@1.0.4
|
||||
mobile-status-bar@1.0.12
|
||||
modules@0.7.5
|
||||
modules-runtime@0.7.5
|
||||
modules@0.7.6
|
||||
modules-runtime@0.7.6
|
||||
momentjs:moment@2.14.4
|
||||
mongo@1.1.10
|
||||
mongo@1.1.12
|
||||
mongo-id@1.0.5
|
||||
mrt:moment@2.8.1
|
||||
natestrauser:select2@4.0.2
|
||||
npm-mongo@1.5.45
|
||||
natestrauser:select2@4.0.3
|
||||
npm-mongo@1.5.49
|
||||
observe-sequence@1.0.12
|
||||
ohif:core@0.0.1
|
||||
ordered-dict@1.0.8
|
||||
orthanc-remote@0.0.1
|
||||
peppelg:bootstrap-3-modal@1.0.4
|
||||
practicalmeteor:chai@2.1.0_1
|
||||
practicalmeteor:loglevel@1.2.0_2
|
||||
promise@0.8.3
|
||||
promise@0.8.4
|
||||
random@1.0.10
|
||||
reactive-dict@1.1.8
|
||||
reactive-var@1.0.10
|
||||
@ -83,14 +85,15 @@ retry@1.0.8
|
||||
routepolicy@1.0.11
|
||||
rwatts:uuid@0.1.0
|
||||
session@1.1.6
|
||||
shell-server@0.2.1
|
||||
silentcicero:jszip@0.0.4
|
||||
spacebars@1.0.12
|
||||
spacebars-compiler@1.0.12
|
||||
standard-app-packages@1.0.9
|
||||
standard-minifier-css@1.1.8
|
||||
standard-minifier-js@1.1.8
|
||||
stylus@2.513.4
|
||||
templating@1.2.13
|
||||
standard-minifier-css@1.2.0
|
||||
standard-minifier-js@1.2.0
|
||||
stylus@2.513.5
|
||||
templating@1.2.14
|
||||
templating-tools@1.0.4
|
||||
tracker@1.1.0
|
||||
twbs:bootstrap@3.3.6
|
||||
@ -99,6 +102,7 @@ underscore@1.0.9
|
||||
url@1.0.10
|
||||
validatejs@0.0.1
|
||||
viewerbase@0.0.1
|
||||
webapp@1.3.10
|
||||
wadoproxy@0.0.1
|
||||
webapp@1.3.11
|
||||
webapp-hashing@1.0.9
|
||||
worklist@0.0.1
|
||||
|
||||
@ -27,11 +27,11 @@ $lesionsSidebarMenuWidth = 450px
|
||||
transform(translateX(0%))
|
||||
|
||||
.sidebar-left
|
||||
max-width: $studiesSidebarMenuWidth
|
||||
order: 1
|
||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
flex: 1
|
||||
margin-left: - $studiesSidebarMenuWidth
|
||||
border-right: $uiBorderThickness $uiBorderColor solid
|
||||
max-width: $studiesSidebarMenuWidth
|
||||
order: 1
|
||||
|
||||
&.sidebar-open
|
||||
margin-left: 0
|
||||
@ -62,7 +62,7 @@ $lesionsSidebarMenuWidth = 450px
|
||||
max-width: $lesionsSidebarMenuWidth + 270px
|
||||
|
||||
&:before
|
||||
background-color: $uiBorderColor
|
||||
theme('background-color', '$uiBorderColor')
|
||||
content: ''
|
||||
display: block
|
||||
height: 100%
|
||||
@ -75,6 +75,6 @@ $lesionsSidebarMenuWidth = 450px
|
||||
margin-right: 0
|
||||
|
||||
.studiesListedChanger
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
padding: 20px 10px
|
||||
text-align: center
|
||||
border-bottom: $uiBorderThickness $uiBorderColor solid
|
||||
|
||||
@ -25,4 +25,5 @@
|
||||
</div>
|
||||
{{> worklist }}
|
||||
{{> aboutModal }}
|
||||
{{> viewSeriesDetailsModal }}
|
||||
</template>
|
||||
@ -9,8 +9,8 @@ $expandedHeight = 160px
|
||||
|
||||
.topBar
|
||||
height: $topBarHeight
|
||||
color: $textPrimaryColor
|
||||
background-color: $primaryBackgroundColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
transition(all 0.5s ease)
|
||||
|
||||
.brandSection
|
||||
@ -26,14 +26,14 @@ $expandedHeight = 160px
|
||||
display: inline-block
|
||||
font-family: $logoFontFamily
|
||||
font-weight: $logoFontWeight
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
line-height: 30px
|
||||
|
||||
.studyListLinkSection
|
||||
border-left: $uiBorderThickness solid $uiBorderColor;
|
||||
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
|
||||
.btn
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
cursor: pointer
|
||||
font-size: 13px
|
||||
font-weight: 500
|
||||
@ -41,10 +41,10 @@ $expandedHeight = 160px
|
||||
margin-top: 3px
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
&.studyList
|
||||
background-color: rgba(21, 25, 30, 0.7)
|
||||
@ -75,5 +75,5 @@ $expandedHeight = 160px
|
||||
.tab-pane
|
||||
.viewerContainer
|
||||
.loadingTextDiv
|
||||
color: $textSecondaryColor
|
||||
font-size: 30px
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 30px
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import "{design}/app"
|
||||
|
||||
.toolbarSection
|
||||
border-bottom: $uiBorderColor $uiBorderThickness solid
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
flex: 0 0 auto
|
||||
height: $toolbarHeight
|
||||
overflow: hidden
|
||||
@ -11,4 +11,4 @@
|
||||
width: 100%
|
||||
|
||||
&.expanded
|
||||
height: $toolbarHeight + $toolbarDrawerHeight
|
||||
height: $toolbarHeight + $toolbarDrawerHeight
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
width: 100%
|
||||
|
||||
.loadingTextDiv
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 30px
|
||||
|
||||
@ -26,7 +26,8 @@ Package.onUse(function (api) {
|
||||
|
||||
api.use([
|
||||
'zuuk:stale-session@1.0.8',
|
||||
'typ:accounts-ldap'
|
||||
'typ:accounts-ldap',
|
||||
'random'
|
||||
], ['client', 'server']);
|
||||
|
||||
api.addFiles([
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import "{design}/app"
|
||||
|
||||
$height = 25px
|
||||
$textColorActive = #2D2D2D
|
||||
$textColorButtonActive = #2D2D2D
|
||||
|
||||
.roundedButtonGroup
|
||||
|
||||
@ -15,9 +15,9 @@ $textColorActive = #2D2D2D
|
||||
|
||||
.roundedButton
|
||||
align-items: center
|
||||
background-color: $uiGrayDark
|
||||
border: 2px $uiBorderColorDark solid
|
||||
color: $textSecondaryColor
|
||||
theme('background-color', '$uiGrayDark')
|
||||
theme('border', '2px solid $uiBorderColorDark')
|
||||
theme('color', '$textSecondaryColor')
|
||||
display: flex
|
||||
font-size: 11px
|
||||
font-weight: 500
|
||||
@ -29,19 +29,19 @@ $textColorActive = #2D2D2D
|
||||
transition: transition($sidebarTransition)
|
||||
|
||||
svg
|
||||
fill: $defaultColor
|
||||
stroke: $defaultColor
|
||||
theme('fill', '$defaultColor')
|
||||
theme('stroke', '$defaultColor')
|
||||
|
||||
svg
|
||||
span
|
||||
margin: 0 2px
|
||||
|
||||
|
||||
i
|
||||
line-height: 15px
|
||||
font-size: 15px
|
||||
|
||||
.bottomLabel
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 12px
|
||||
font-weight: 500
|
||||
line-height: 12px
|
||||
@ -58,16 +58,16 @@ $textColorActive = #2D2D2D
|
||||
border-top-right-radius: $height
|
||||
|
||||
&:hover .roundedButton
|
||||
background-color: $boxBackgroundColor
|
||||
color: $uiGrayDark
|
||||
theme('color', '$uiGrayDark')
|
||||
theme('background-color', '$boxBackgroundColor')
|
||||
|
||||
&.active .roundedButton
|
||||
background-color: $activeColor
|
||||
border-color: $uiBorderColorActive
|
||||
color: $textColorActive
|
||||
theme('background-color', '$activeColor')
|
||||
theme('border-color', '$uiBorderColorActive')
|
||||
color: $textColorButtonActive
|
||||
|
||||
&:hover .roundedButton
|
||||
&.active .roundedButton
|
||||
svg
|
||||
fill: $uiGrayDark
|
||||
stroke: $uiGrayDark
|
||||
theme('fill', '$uiGrayDark')
|
||||
theme('stroke', '$uiGrayDark')
|
||||
|
||||
@ -18,7 +18,9 @@ Package.onUse(function(api) {
|
||||
'styles/imports/mixins.styl',
|
||||
'styles/imports/spacings.styl',
|
||||
'styles/imports/variables.styl',
|
||||
'styles/imports/theming.styl',
|
||||
'styles/imports/theme-tide.styl',
|
||||
'styles/imports/theme-tigerlilly.styl'
|
||||
], 'client', {
|
||||
isImport: true
|
||||
});
|
||||
@ -35,7 +37,8 @@ Package.onUse(function(api) {
|
||||
api.addFiles([
|
||||
'styles/components/radio.styl',
|
||||
'styles/components/select2.styl',
|
||||
'styles/components/selectTree.styl'
|
||||
'styles/components/selectTree.styl',
|
||||
'styles/components/states.styl'
|
||||
], 'client');
|
||||
|
||||
// Rounded Button Group
|
||||
|
||||
@ -2,11 +2,26 @@
|
||||
|
||||
html body
|
||||
font-family: 'Roboto', 'OpenSans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif
|
||||
// Try to fix LT-273, need a monitor to test on though.
|
||||
//text-rendering: optimizeLegibility
|
||||
|
||||
html hr
|
||||
border-top: 1px solid $uiBorderColor
|
||||
theme('border-top', '1px solid $uiBorderColor')
|
||||
|
||||
label.form-group
|
||||
width: 100%
|
||||
|
||||
&>span.select2
|
||||
display: block
|
||||
width: 100% !important
|
||||
|
||||
span.select2-selection
|
||||
min-height: 34px
|
||||
|
||||
span.select2-selection__rendered
|
||||
height: 34px
|
||||
line-height: 34px
|
||||
|
||||
span.select2-selection__arrow
|
||||
height: 34px
|
||||
|
||||
.center-table
|
||||
display: table
|
||||
@ -32,9 +47,9 @@ html hr
|
||||
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
background: $primaryBackgroundColor
|
||||
border-color: $uiBorderColor
|
||||
color: $textSecondaryColor
|
||||
theme('background', '$primaryBackgroundColor')
|
||||
theme('border-color', '$uiBorderColor')
|
||||
theme('color', '$textSecondaryColor')
|
||||
|
||||
.modal-header, .modal-footer
|
||||
border-color: $uiBorderColor
|
||||
theme('border-color', '$uiBorderColor')
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
.group-radio
|
||||
label
|
||||
cursor: pointer
|
||||
|
||||
|
||||
input
|
||||
height: 0
|
||||
width: 0
|
||||
visibility: hidden
|
||||
|
||||
|
||||
span
|
||||
padding-left: 23px
|
||||
position: relative
|
||||
@ -23,14 +23,14 @@
|
||||
top: 50%
|
||||
transform(translateY(-50%))
|
||||
width: 16px
|
||||
|
||||
|
||||
input:focus + span:before
|
||||
// TODO: [design] define a outline for the design
|
||||
theme('box-shadow', '0 0 2px 2px $textSecondaryColor')
|
||||
outline: none
|
||||
box-shadow: 0 0 2px 2px $textSecondaryColor
|
||||
|
||||
|
||||
input:checked + span:after
|
||||
background: $uiBorderColorDark
|
||||
theme('background', '$uiBorderColorDark')
|
||||
border-radius: 5px
|
||||
content: ''
|
||||
height: 10px
|
||||
|
||||
@ -22,8 +22,8 @@ span.select2.select2-container
|
||||
padding-left: 11px
|
||||
|
||||
span.select2-selection__arrow
|
||||
theme('border-left', '1px solid $primaryBackgroundColor')
|
||||
background-color: $gray1
|
||||
border-left: 1px solid $primaryBackgroundColor
|
||||
border-top-right-radius: $borderRadius
|
||||
border-bottom-right-radius: $borderRadius
|
||||
right: 0
|
||||
@ -42,8 +42,8 @@ span.select2.select2-container
|
||||
placeholder-color($gray4)
|
||||
|
||||
li.select2-selection__choice
|
||||
theme('border-color', '$uiGray')
|
||||
background-color: #FFF
|
||||
border-color: $uiGray
|
||||
border-radius: $borderRadius
|
||||
color: $gray4
|
||||
font-size: 12px
|
||||
|
||||
@ -76,6 +76,7 @@ $gray6 = #303030
|
||||
display: block
|
||||
margin: 0
|
||||
padding: 5px
|
||||
position: relative
|
||||
text-align: center
|
||||
|
||||
span
|
||||
@ -85,6 +86,14 @@ $gray6 = #303030
|
||||
input
|
||||
border-color: $gray5
|
||||
font-weight: normal
|
||||
padding-left: 34px
|
||||
|
||||
& ~ i
|
||||
color: $gray1
|
||||
font-size: 18px
|
||||
left: 16px
|
||||
position: absolute
|
||||
top: 37px
|
||||
|
||||
.tree-breadcrumb
|
||||
line-height: 32px
|
||||
@ -146,7 +155,6 @@ $gray6 = #303030
|
||||
|
||||
&.active
|
||||
box-shadow: 0 0 0 200px white, inset 0 0 0 200px white
|
||||
position: fixed
|
||||
transition(box-shadow 0.3s ease)
|
||||
z-index: 0
|
||||
|
||||
@ -172,7 +180,7 @@ $gray6 = #303030
|
||||
border-radius: 5px
|
||||
color: white
|
||||
opacity: 0.9
|
||||
padding: 5px 12px 12px
|
||||
padding: 0 15px 12px
|
||||
position: absolute
|
||||
top: 50%
|
||||
transform(translateY(-50%))
|
||||
@ -180,13 +188,21 @@ $gray6 = #303030
|
||||
|
||||
h5.title
|
||||
color: $gray5
|
||||
font-size: 12px
|
||||
font-weight: normal
|
||||
line-height: 20px
|
||||
margin: 0
|
||||
margin: 12px 0 16px
|
||||
|
||||
label
|
||||
cursor: pointer
|
||||
display: block
|
||||
font-weight: 300
|
||||
line-height: 26px
|
||||
margin: 0
|
||||
padding-left: 3px
|
||||
transition(padding 0.3s ease)
|
||||
|
||||
&:hover
|
||||
padding-left: 0
|
||||
|
||||
.select-tree-root
|
||||
|
||||
@ -218,7 +234,7 @@ $gray6 = #303030
|
||||
.content
|
||||
margin-left: 0
|
||||
|
||||
&.interacted
|
||||
&.interacted, &.selected
|
||||
|
||||
.select-tree-common
|
||||
z-index: 1
|
||||
|
||||
29
Packages/design/styles/components/states.styl
Normal file
29
Packages/design/styles/components/states.styl
Normal file
@ -0,0 +1,29 @@
|
||||
@import "{design}/app"
|
||||
|
||||
.state-error
|
||||
&+.tooltip
|
||||
|
||||
.tooltip-inner
|
||||
color: white
|
||||
theme('background-color', '$uiStateErrorBorder')
|
||||
|
||||
&.top .tooltip-arrow
|
||||
theme('border-top-color', '$uiStateErrorBorder')
|
||||
&.right .tooltip-arrow
|
||||
theme('border-right-color', '$uiStateErrorBorder')
|
||||
&.bottom .tooltip-arrow
|
||||
theme('border-bottom-color', '$uiStateErrorBorder')
|
||||
&.left .tooltip-arrow
|
||||
theme('border-left-color', '$uiStateErrorBorder')
|
||||
|
||||
|
||||
&:not(.component-group)
|
||||
&.form-control, .form-control
|
||||
theme('background-color', '$uiStateError')
|
||||
theme('border-color', '$uiStateErrorBorder')
|
||||
theme('color', '$uiStateErrorText')
|
||||
|
||||
.select2-selection
|
||||
theme('background-color', '$uiStateError')
|
||||
theme('border-color', '$uiStateErrorBorder')
|
||||
theme('color', '$uiStateErrorText')
|
||||
@ -1,54 +1,34 @@
|
||||
// Common pallete
|
||||
$uiYellow = #E29E4A
|
||||
$uiSkyBlue = #6FBDE2
|
||||
$themes['tide'] = {
|
||||
// Common pallete
|
||||
$uiYellow: #E29E4A
|
||||
$uiSkyBlue: #6FBDE2
|
||||
|
||||
$uiLightGray = #516873
|
||||
$uiGray = #263340
|
||||
$uiGrayDark = #16202B
|
||||
$uiGrayDarker = #151A1F
|
||||
$uiGrayDarkest = #14191E
|
||||
// State pallete
|
||||
$uiStateError: #FFCCCC
|
||||
$uiStateErrorBorder: #993333
|
||||
$uiStateErrorText: #661111
|
||||
|
||||
// Interface UI Colors
|
||||
$defaultColor = #9cd0fe
|
||||
$hoverColor = #ffffff
|
||||
$activeColor = #00a4d9
|
||||
$uiBorderColor = #436270
|
||||
$uiBorderColorDark = #3C5D80
|
||||
$uiBorderColorActive = #00a4d9
|
||||
$primaryBackgroundColor = #000000
|
||||
$boxBackgroundColor = #344a61
|
||||
$boxBackgroundColorDark = #22374D
|
||||
$uiLightGray: #516873
|
||||
$uiGray: #263340
|
||||
$uiGrayDark: #16202B
|
||||
$uiGrayDarker: #151A1F
|
||||
$uiGrayDarkest: #14191E
|
||||
|
||||
// Text Colors
|
||||
$textColorActive = black //#89bae5
|
||||
$textPrimaryColor = #ffffff
|
||||
$textSecondaryColor = #6a8fb1
|
||||
// Interface UI Colors
|
||||
$defaultColor: #9cd0fe
|
||||
$hoverColor: #ffffff
|
||||
$activeColor: #00a4d9
|
||||
$uiBorderColor: #436270
|
||||
$uiBorderColorDark: #3C5D80
|
||||
$uiBorderColorActive: #00a4d9
|
||||
$primaryBackgroundColor: #000000
|
||||
$boxBackgroundColor: #344a61
|
||||
|
||||
// Other Colors
|
||||
$menuBackgroundColor = #F2F2F2
|
||||
$imageSliderColor = #163239
|
||||
// Text Colors
|
||||
$textColorActive: black //#89bae5
|
||||
$textPrimaryColor: #ffffff
|
||||
$textSecondaryColor: #6a8fb1
|
||||
|
||||
// Viewport Settings
|
||||
$viewportBorderThickness = 1px
|
||||
$viewportBorderColor = $uiBorderColorDark
|
||||
$viewportBorderColorHover = $uiBorderColor
|
||||
$viewportBorderColorActive = $uiBorderColorActive
|
||||
|
||||
// Sizes
|
||||
$topBarHeight = 40px
|
||||
$toolbarHeight = 78px
|
||||
$toolbarDrawerHeight = 62px
|
||||
|
||||
// Thicknesses
|
||||
$uiBorderThickness = 1px
|
||||
|
||||
// Fonts
|
||||
$logoFontFamily = "Sanchez"
|
||||
$logoFontWeight = 300
|
||||
|
||||
// Transitions
|
||||
$transitionDuration = 0.3s
|
||||
$transitionEffect = ease
|
||||
$sidebarTransition = all $transitionDuration $transitionEffect
|
||||
$studiesSidebarMenuWidth = 307px
|
||||
$lesionsSidebarMenuWidth = 323px
|
||||
// Other Colors
|
||||
$imageSliderColor: #163239
|
||||
}
|
||||
|
||||
@ -1,54 +1,34 @@
|
||||
// Common pallete
|
||||
$uiYellow = #E29E4A
|
||||
$uiSkyBlue = #6FBDE2
|
||||
$themes['tigerlilly'] = {
|
||||
// Common pallete
|
||||
$uiYellow: #E29E4A
|
||||
$uiSkyBlue: #6FBDE2
|
||||
|
||||
$uiLightGray = #516873
|
||||
$uiGray = #263340
|
||||
$uiGrayDark = #16202B
|
||||
$uiGrayDarker = #151A1F
|
||||
$uiGrayDarkest = #14191E
|
||||
// State pallete
|
||||
$uiStateError: #FFCCCC
|
||||
$uiStateErrorBorder: #CC6666
|
||||
$uiStateErrorText: #661111
|
||||
|
||||
// Interface UI Colors
|
||||
$defaultColor = #98ceff
|
||||
$hoverColor = #ffffff
|
||||
$activeColor = #ff8a3d
|
||||
$uiBorderColor = #744b71
|
||||
$uiBorderColorDark = #744b71
|
||||
$uiBorderColorActive = #ff8a3d
|
||||
$primaryBackgroundColor = #000000
|
||||
$boxBackgroundColor = #5b3a59
|
||||
$boxBackgroundColorDark = #4b2f40
|
||||
$uiLightGray: #516873
|
||||
$uiGray: #263340
|
||||
$uiGrayDark: #16202B
|
||||
$uiGrayDarker: #151A1F
|
||||
$uiGrayDarkest: #14191E
|
||||
|
||||
// Text Colors
|
||||
$textColorActive = #ff8a3d
|
||||
$textPrimaryColor = #ffffff
|
||||
$textSecondaryColor = #6a8fb1
|
||||
// Interface UI Colors
|
||||
$defaultColor: #98ceff
|
||||
$hoverColor: #ffffff
|
||||
$activeColor: #ff8a3d
|
||||
$uiBorderColor: #744b71
|
||||
$uiBorderColorDark: #744b71
|
||||
$uiBorderColorActive: #ff8a3d
|
||||
$primaryBackgroundColor: #000000
|
||||
$boxBackgroundColor: #5b3a59
|
||||
|
||||
// Other Colors
|
||||
$menuBackgroundColor = #F2F2F2
|
||||
$imageSliderColor = #4b2c3c //#163239
|
||||
// Text Colors
|
||||
$textColorActive: black
|
||||
$textPrimaryColor: #ffffff
|
||||
$textSecondaryColor: #6a8fb1
|
||||
|
||||
// Viewport Settings
|
||||
$viewportBorderThickness = 1px
|
||||
$viewportBorderColor = $uiBorderColorDark
|
||||
$viewportBorderColorHover = $uiBorderColor
|
||||
$viewportBorderColorActive = $uiBorderColorActive
|
||||
|
||||
// Sizes
|
||||
$topBarHeight = 40px
|
||||
$toolbarHeight = 78px
|
||||
$toolbarDrawerHeight = 62px
|
||||
|
||||
// Thicknesses
|
||||
$uiBorderThickness = 1px
|
||||
|
||||
// Fonts
|
||||
$logoFontFamily = "Sanchez"
|
||||
$logoFontWeight = 300
|
||||
|
||||
// Transitions
|
||||
$transitionDuration = 0.3s
|
||||
$transitionEffect = ease
|
||||
$sidebarTransition = all $transitionDuration $transitionEffect
|
||||
$studiesSidebarMenuWidth = 307px
|
||||
$lesionsSidebarMenuWidth = 323px
|
||||
// Other Colors
|
||||
$imageSliderColor: #4b2c3c //#163239
|
||||
}
|
||||
|
||||
32
Packages/design/styles/imports/theming.styl
Normal file
32
Packages/design/styles/imports/theming.styl
Normal file
@ -0,0 +1,32 @@
|
||||
$themes = {}
|
||||
$defaultTheme = 'tide'
|
||||
|
||||
@import "./theme-tide.styl"
|
||||
@import "./theme-tigerlilly.styl"
|
||||
|
||||
parseSpaceVars($theme, $value)
|
||||
$valueSplit = split(' ', $value)
|
||||
$list = ''
|
||||
pop($list)
|
||||
for $property in $valueSplit
|
||||
if ($theme[$property])
|
||||
push($list, $theme[$property])
|
||||
else
|
||||
push($list, $property)
|
||||
join(' ', $list)
|
||||
|
||||
parseCommaVars($theme, $value)
|
||||
$valueSplit = split(',', $value)
|
||||
$list = ''
|
||||
pop($list)
|
||||
for $sentence in $valueSplit
|
||||
push($list, parseSpaceVars($theme, $sentence))
|
||||
unquote(join(',', $list))
|
||||
|
||||
theme($property, $value)
|
||||
/ {selector()}
|
||||
{$property}: parseCommaVars($themes[$defaultTheme], $value)
|
||||
for $themeName, $theme in $themes
|
||||
for $selectorPiece in split(',', selector())
|
||||
/ body.theme-{$themeName} {$selectorPiece}
|
||||
{$property}: parseCommaVars($theme, $value)
|
||||
@ -1,2 +1,22 @@
|
||||
//@import "./theme-tigerlilly.styl"
|
||||
@import "./theme-tide.styl"
|
||||
@import "./theming.styl"
|
||||
|
||||
// Sizes
|
||||
$topBarHeight = 40px
|
||||
$toolbarHeight = 78px
|
||||
$toolbarDrawerHeight = 62px
|
||||
$studiesSidebarMenuWidth = 307px
|
||||
$lesionsSidebarMenuWidth = 323px
|
||||
|
||||
// Fonts
|
||||
$logoFontFamily = "Sanchez"
|
||||
$logoFontWeight = 300
|
||||
|
||||
// Transitions
|
||||
$transitionDuration = 0.3s
|
||||
$transitionEffect = ease
|
||||
$sidebarTransition = all $transitionDuration $transitionEffect
|
||||
|
||||
|
||||
// Thicknesses
|
||||
$viewportBorderThickness = 1px
|
||||
$uiBorderThickness = 1px
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
$height = 20px
|
||||
|
||||
#protocolEditor
|
||||
theme('background', '$primaryBackgroundColor')
|
||||
height: 100%
|
||||
width: 450px
|
||||
padding: 10px 0
|
||||
position: absolute
|
||||
top: 0
|
||||
background: $primaryBackgroundColor
|
||||
|
||||
.navigationButtons
|
||||
ul
|
||||
@ -35,27 +35,27 @@ $height = 20px
|
||||
cursor: pointer
|
||||
text-decoration: none
|
||||
outline: none
|
||||
background-color: $uiGrayDark
|
||||
border: 2px $uiBorderColorDark solid
|
||||
color: $textSecondaryColor
|
||||
theme('background-color', '$uiGrayDark')
|
||||
theme('border', '2px solid $uiBorderColorDark')
|
||||
theme('color', '$textSecondaryColor')
|
||||
transition: transition($sidebarTransition)
|
||||
border-radius: $height
|
||||
|
||||
&.active a
|
||||
background-color: $activeColor
|
||||
border-color: $uiBorderColorActive
|
||||
color: $textColorActive
|
||||
theme('background-color', '$activeColor')
|
||||
theme('border-color', '$uiBorderColorActive')
|
||||
theme('color', '$textColorActive')
|
||||
transition: transition($sidebarTransition)
|
||||
|
||||
p
|
||||
h2
|
||||
h3
|
||||
h4
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
label
|
||||
ul
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
font-weight: 400
|
||||
|
||||
label
|
||||
@ -68,7 +68,7 @@ $height = 20px
|
||||
width: 40%
|
||||
border: none
|
||||
background: #212121
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
button.btn
|
||||
@ -85,11 +85,11 @@ $height = 20px
|
||||
bottom: 0
|
||||
width: 100%
|
||||
margin-bottom: 0
|
||||
background: $uiGrayDarker
|
||||
theme('background', '$uiGrayDarker')
|
||||
|
||||
p
|
||||
font-size: 8pt
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
margin: 0 10px
|
||||
display: inline-block
|
||||
|
||||
@ -107,11 +107,11 @@ $height = 20px
|
||||
#selectProtocol
|
||||
text-align: center
|
||||
|
||||
.btn-file
|
||||
.btn-file
|
||||
position: relative
|
||||
overflow: hidden
|
||||
|
||||
.btn-file input[type=file]
|
||||
|
||||
.btn-file input[type=file]
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
@ -141,4 +141,4 @@ $height = 20px
|
||||
padding: 40px
|
||||
|
||||
h3
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
@import "{design}/app.styl"
|
||||
|
||||
.ruleEntryDialog
|
||||
theme('background', '$uiGrayDarkest')
|
||||
theme('border', '1px solid $uiBorderColor')
|
||||
theme('color', '$textSecondaryColor')
|
||||
display: none
|
||||
position: absolute
|
||||
top: 0
|
||||
@ -14,12 +17,8 @@
|
||||
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
|
||||
@ -44,4 +43,4 @@
|
||||
color: black
|
||||
height: 30px
|
||||
border-radius: 2px
|
||||
border: 0
|
||||
border: 0
|
||||
|
||||
@ -4,7 +4,7 @@ table.ruleTable
|
||||
thead
|
||||
tr
|
||||
th
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
th:first-child
|
||||
@ -13,7 +13,7 @@ table.ruleTable
|
||||
tbody
|
||||
tr
|
||||
td
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
.failWarning
|
||||
@ -26,10 +26,10 @@ table.ruleTable
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
td:first-child
|
||||
text-align: left
|
||||
@ -37,14 +37,14 @@ table.ruleTable
|
||||
.addRuleContainer
|
||||
margin: 10px 0
|
||||
text-align: center
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
.addRule
|
||||
cursor: pointer
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
@ -1,6 +1,9 @@
|
||||
@import "{design}/app.styl"
|
||||
|
||||
.settingEntryDialog
|
||||
theme('border', '1px solid $uiBorderColor')
|
||||
theme('background', '$uiGrayDarkest')
|
||||
theme('color', '$textSecondaryColor')
|
||||
display: none
|
||||
position: absolute
|
||||
top: 0
|
||||
@ -13,12 +16,8 @@
|
||||
margin: auto
|
||||
padding: 10px
|
||||
outline: none
|
||||
|
||||
opacity: 0.95
|
||||
border-radius: 8px
|
||||
border: 1px solid $uiBorderColor
|
||||
background: $uiGrayDarkest
|
||||
color: $textSecondaryColor
|
||||
|
||||
.dialogContent
|
||||
text-align: center
|
||||
@ -43,4 +42,4 @@
|
||||
color: black
|
||||
height: 30px
|
||||
border-radius: 2px
|
||||
border: 0
|
||||
border: 0
|
||||
|
||||
@ -4,7 +4,7 @@ table.settingsTable
|
||||
thead
|
||||
tr
|
||||
th
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
th:first-child
|
||||
@ -15,7 +15,7 @@ table.settingsTable
|
||||
|
||||
tr
|
||||
td
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
.editSetting
|
||||
@ -24,10 +24,10 @@ table.settingsTable
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
td:first-child
|
||||
text-align: left
|
||||
@ -35,14 +35,14 @@ table.settingsTable
|
||||
.addSettingContainer
|
||||
margin: 10px 0
|
||||
text-align: center
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
.addSetting
|
||||
cursor: pointer
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
@ -14,19 +14,19 @@
|
||||
|
||||
h3
|
||||
label
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
label
|
||||
margin-right: 10px
|
||||
width: 25%
|
||||
|
||||
input
|
||||
theme('background-color', '$boxBackgroundColor')Dark
|
||||
min-width: 50px
|
||||
width: 40%
|
||||
border: none
|
||||
background: $boxBackgroundColorDark
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
.stageEditorSection
|
||||
margin: 30px 0
|
||||
margin: 30px 0
|
||||
|
||||
@ -8,14 +8,14 @@
|
||||
padding: 3px
|
||||
|
||||
span
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&.active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.sortable-handle
|
||||
cursor: move
|
||||
@ -36,44 +36,44 @@
|
||||
|
||||
.deleteStage
|
||||
cursor: pointer
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.addStage
|
||||
margin: 10px 0
|
||||
text-align: center
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
#addStage
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.moveStageButtons
|
||||
margin: 10px 0
|
||||
text-align: center
|
||||
|
||||
a
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
text-decoration: none
|
||||
transition(all 0.1s ease)
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
&[disabled="true"]
|
||||
opacity: 0.7
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
@import "{design}/app.styl"
|
||||
|
||||
.textEntryDialog
|
||||
theme('border', '1px solid $uiBorderColor')
|
||||
theme('background', '$uiGrayDarkest')
|
||||
theme('color', '$textSecondaryColor')
|
||||
display: none
|
||||
position: absolute
|
||||
top: 0
|
||||
@ -13,12 +16,8 @@
|
||||
margin: auto
|
||||
padding: 10px
|
||||
outline: none
|
||||
|
||||
opacity: 0.95
|
||||
border-radius: 8px
|
||||
border: 1px solid $uiBorderColor
|
||||
background: $uiGrayDarkest
|
||||
color: $textSecondaryColor
|
||||
|
||||
.dialogContent
|
||||
margin-bottom: 10px
|
||||
@ -36,4 +35,4 @@
|
||||
color: black
|
||||
height: 30px
|
||||
border-radius: 2px
|
||||
border: 0
|
||||
border: 0
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
|
||||
// Servers describe the DICOM servers configurations
|
||||
Servers = new Mongo.Collection('servers');
|
||||
|
||||
Timepoints = new Mongo.Collection('timepoints');
|
||||
Studies = new Mongo.Collection('studies');
|
||||
Measurements = new Mongo.Collection('measurements');
|
||||
@ -12,6 +15,5 @@ ImageMeasurements = new Mongo.Collection('imageMeasurements');
|
||||
// panel, and represents items such as data quality,
|
||||
AdditionalFindings = new Mongo.Collection('additionalFindings');
|
||||
|
||||
Servers = new Mongo.Collection('servers');
|
||||
WorklistSubscriptions = ['studies', 'timepoints'];
|
||||
Reviewers = new Mongo.Collection('reviewers');
|
||||
|
||||
@ -26,8 +26,14 @@ class TimepointApi {
|
||||
});
|
||||
}
|
||||
|
||||
// Return the prior timepoint
|
||||
prior() {
|
||||
const latestDate = this.current().latestDate;
|
||||
const current = this.current();
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const latestDate = current.latestDate;
|
||||
return this.timepoints.findOne({
|
||||
latestDate: {
|
||||
$lt: latestDate
|
||||
@ -41,9 +47,15 @@ class TimepointApi {
|
||||
|
||||
// Return only the current and prior Timepoints
|
||||
currentAndPrior() {
|
||||
let timepoints = [this.current()];
|
||||
const timepoints = [];
|
||||
|
||||
const current = this.current();
|
||||
if (current) {
|
||||
timepoints.push(current);
|
||||
}
|
||||
|
||||
const prior = this.prior();
|
||||
if (prior) {
|
||||
if (current && prior && prior._id !== current._id) {
|
||||
timepoints.push(prior);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ActiveEntry } from 'meteor/clinical:active-entry';
|
||||
|
||||
|
||||
Template.entrySignIn.hooks({
|
||||
|
||||
rendered: function () {
|
||||
// Create Test Drive button dynamically
|
||||
let btnTestDrive = $('<button/>', {
|
||||
id: 'btnTestDrive',
|
||||
text: 'Test Drive',
|
||||
class: 'btn btn-primary',
|
||||
style: 'position: absolute; width: 150px; top: 20px; right: 20px; padding-left: 0;',
|
||||
title: 'Login with Demo User',
|
||||
click: function () {
|
||||
// Login with demo user
|
||||
ActiveEntry.signIn('demo@ohif.org', '12345678aA*');
|
||||
}
|
||||
});
|
||||
|
||||
const entrySignIn = this.find('#entrySignIn');
|
||||
$(entrySignIn).append(btnTestDrive);
|
||||
}
|
||||
|
||||
});
|
||||
@ -15,7 +15,7 @@
|
||||
key='regionsOfMetastaticDisease'
|
||||
multiple=true
|
||||
options=(clone
|
||||
placeholder='Choose a region...'
|
||||
placeholder='Choose a region'
|
||||
allowClear=true
|
||||
)
|
||||
}}
|
||||
|
||||
@ -22,22 +22,22 @@
|
||||
display: none
|
||||
|
||||
.header
|
||||
theme('background-color', '$uiGray')
|
||||
theme('color', '$textPrimaryColor')
|
||||
height: 33px
|
||||
line-height: 33px
|
||||
font-weight: bold
|
||||
font-size: 14px
|
||||
padding: 1px 13px 0
|
||||
color: $textPrimaryColor
|
||||
background-color: $uiGray
|
||||
|
||||
.form-group
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
margin-bottom: 0
|
||||
padding: 7px 27px 7px 11px
|
||||
width: 100%
|
||||
|
||||
&:not(:last-child)
|
||||
border-bottom: $uiBorderThickness solid $uiBorderColorDark
|
||||
theme('border-bottom', '%s solid $uiBorderColorDark' % $uiBorderThickness)
|
||||
|
||||
& > .wrapperText
|
||||
display: block
|
||||
@ -81,21 +81,21 @@
|
||||
.buttonSection
|
||||
cursor: pointer
|
||||
height: 90px
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
.svgContainer
|
||||
svg
|
||||
fill: $hoverColor
|
||||
theme('fill', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.svgContainer
|
||||
svg
|
||||
fill: $activeColor
|
||||
theme('fill', '$activeColor')
|
||||
|
||||
div
|
||||
float: left
|
||||
@ -112,4 +112,4 @@
|
||||
svg
|
||||
width: 36px
|
||||
height: 36px
|
||||
fill: $textPrimaryColor
|
||||
theme('fill', '$textPrimaryColor')
|
||||
|
||||
@ -7,7 +7,14 @@ Template.caseProgress.onCreated(() => {
|
||||
instance.progressText = new ReactiveVar();
|
||||
instance.isLocked = new ReactiveVar();
|
||||
|
||||
// Get the current timepoint
|
||||
const current = instance.data.timepointApi.current();
|
||||
|
||||
// Stop here if no timepoint was found
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current.timepointId) {
|
||||
console.warn('Case has no timepointId');
|
||||
return;
|
||||
|
||||
@ -13,15 +13,15 @@
|
||||
margin-left: 22px
|
||||
|
||||
h5
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
line-height: 46px
|
||||
margin: 0
|
||||
font-size: 15px
|
||||
font-weight: bold
|
||||
|
||||
button.btn
|
||||
background-color: $activeColor
|
||||
border: 1px solid $uiBorderColorActive
|
||||
theme('background-color', '$activeColor')
|
||||
theme('border', '1px solid $uiBorderColorActive')
|
||||
color: #000
|
||||
cursor: pointer
|
||||
font-size: 15px
|
||||
|
||||
@ -25,11 +25,11 @@
|
||||
transform(translateX(0%))
|
||||
|
||||
.sidebar-left
|
||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
max-width: $studiesSidebarMenuWidth
|
||||
order: 1
|
||||
flex: 1
|
||||
margin-left: - $studiesSidebarMenuWidth
|
||||
border-right: $uiBorderThickness $uiBorderColor solid
|
||||
|
||||
&.sidebar-open
|
||||
margin-left: 0
|
||||
@ -60,7 +60,7 @@
|
||||
max-width: $lesionsSidebarMenuWidth + 270px
|
||||
|
||||
&:before
|
||||
background-color: $uiBorderColor
|
||||
theme('background-color', '$uiBorderColor')
|
||||
content: ''
|
||||
display: block
|
||||
height: 100%
|
||||
@ -73,6 +73,6 @@
|
||||
margin-right: 0
|
||||
|
||||
.studiesListedChanger
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
padding: 20px 10px
|
||||
text-align: center
|
||||
border-bottom: $uiBorderThickness $uiBorderColor solid
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
Template.lastLoginModal.helpers({
|
||||
lastLoginDate: function() {
|
||||
var userLoginDate = ReactiveMethod.call('getPriorLoginDate');
|
||||
if (userLoginDate && userLoginDate.priorLoginDate) {
|
||||
return moment(userLoginDate.priorLoginDate).format("MMMM Do YYYY, HH:mm:ss A");
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
@ -1,13 +1,17 @@
|
||||
<template name="lesionTable">
|
||||
<div id="lesionTableContainer">
|
||||
<div class="lesionTableLayoutChanger viewerRoundedButtonGroup">
|
||||
{{>roundedButtonGroup buttonGroupData}}
|
||||
</div>
|
||||
<div class="lesionTableTimepointHeaderRow">
|
||||
{{#each this.timepoints.get}}
|
||||
{{>lesionTableTimepointHeader}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{>lesionTableView (clone this)}}
|
||||
{{#if this.timepoints.get.length}}
|
||||
<div class="lesionTableLayoutChanger viewerRoundedButtonGroup">
|
||||
{{>roundedButtonGroup buttonGroupData}}
|
||||
</div>
|
||||
<div class="lesionTableTimepointHeaderRow">
|
||||
{{#each this.timepoints.get}}
|
||||
{{>lesionTableTimepointHeader}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{>lesionTableView (clone this)}}
|
||||
{{else}}
|
||||
<h3 class="p-x-1 text-center">No associated timepoint</h3>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import "{design}/app"
|
||||
|
||||
#lesionTableContainer
|
||||
background-color: $primaryBackgroundColor
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
|
||||
@ -22,9 +22,9 @@ $borderColor = rgba(77, 99, 110, 0.81)
|
||||
padding-left: 0
|
||||
|
||||
.header
|
||||
background: $uiGrayDarkest
|
||||
theme('background', '$uiGrayDarkest')
|
||||
theme('color', '$textSecondaryColor')
|
||||
border-bottom: $uiBorderThickness solid $borderColor
|
||||
color: $textSecondaryColor
|
||||
font-weight: 300
|
||||
font-size: 20px
|
||||
height: 55px
|
||||
@ -34,12 +34,12 @@ $borderColor = rgba(77, 99, 110, 0.81)
|
||||
width: 100%
|
||||
|
||||
svg.buttonClose
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
height: 14px
|
||||
position: absolute
|
||||
right: 14px
|
||||
stroke: $defaultColor
|
||||
theme('stroke', '$defaultColor')
|
||||
top: 20px
|
||||
width: 14px
|
||||
|
||||
@ -48,19 +48,19 @@ $borderColor = rgba(77, 99, 110, 0.81)
|
||||
padding-bottom: 20px
|
||||
|
||||
.footer
|
||||
theme('background', '$uiGrayDarkest')
|
||||
border-top: $uiBorderThickness solid $borderColor
|
||||
width: 100%
|
||||
height: 70px
|
||||
position: absolute
|
||||
bottom: 0
|
||||
background: $uiGrayDarkest
|
||||
border-top: $uiBorderThickness solid $borderColor
|
||||
padding: 10px
|
||||
|
||||
.toolbarSectionButton
|
||||
display: inline-block
|
||||
color: $defaultColor
|
||||
fill: $defaultColor
|
||||
stroke: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
theme('fill', '$defaultColor')
|
||||
theme('stroke', '$defaultColor')
|
||||
padding: 0 10px
|
||||
height: $toolbarHeight
|
||||
min-width: 30px
|
||||
@ -85,15 +85,15 @@ $borderColor = rgba(77, 99, 110, 0.81)
|
||||
height: 21px
|
||||
|
||||
&:active, &.active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
svg
|
||||
fill: $activeColor
|
||||
stroke: $activeColor
|
||||
theme('fill', '$activeColor')
|
||||
theme('stroke', '$activeColor')
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
svg
|
||||
fill: $hoverColor
|
||||
stroke: $hoverColor
|
||||
theme('fill', '$hoverColor')
|
||||
theme('stroke', '$hoverColor')
|
||||
|
||||
@ -16,7 +16,14 @@ Template.lesionTableHeaderRow.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
instance.maxNumLesions = new ReactiveVar();
|
||||
|
||||
// Get the current timepoint
|
||||
const current = instance.data.timepointApi.current();
|
||||
|
||||
// Stop here if no timepoint was found
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timepointType = current.timepointType;
|
||||
|
||||
if (!instance.data.currentTimepointId) {
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
$headerRowHeight = 63px
|
||||
|
||||
.lesionTableHeaderRow
|
||||
background-color: $uiGrayDarker
|
||||
color: $textSecondaryColor
|
||||
theme('background-color', '$uiGrayDarker')
|
||||
theme('color', '$textSecondaryColor')
|
||||
display: flex
|
||||
fill: $textSecondaryColor
|
||||
theme('fill', '$textSecondaryColor')
|
||||
height: $headerRowHeight
|
||||
line-height: $headerRowHeight
|
||||
margin-top: 2px
|
||||
@ -35,13 +35,13 @@ $headerRowHeight = 63px
|
||||
max-width: 11px
|
||||
|
||||
&:hover
|
||||
fill: $hoverColor
|
||||
theme('fill', '$hoverColor')
|
||||
|
||||
&:active
|
||||
fill: $activeColor
|
||||
theme('fill', '$activeColor')
|
||||
|
||||
.type
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 22px
|
||||
font-weight: 300
|
||||
line-height: $headerRowHeight
|
||||
@ -49,8 +49,8 @@ $headerRowHeight = 63px
|
||||
text-align: left
|
||||
|
||||
.numberOfLesions
|
||||
theme('color', '$uiSkyBlue')
|
||||
float: right
|
||||
color: $uiSkyBlue
|
||||
font-weight: 300
|
||||
font-size: 40px
|
||||
max-width: 54px
|
||||
@ -63,7 +63,7 @@ $headerRowHeight = 63px
|
||||
text-align: right
|
||||
|
||||
.maxNumLesions
|
||||
background-color: $textSecondaryColor
|
||||
theme('background-color', '$textSecondaryColor')
|
||||
border-radius: 3px
|
||||
color: black
|
||||
display: table
|
||||
@ -79,5 +79,5 @@ $headerRowHeight = 63px
|
||||
|
||||
&.warning
|
||||
.maxNumLesions
|
||||
color: $textPrimaryColor
|
||||
background-color: $uiYellow
|
||||
theme('background-color', '$uiYellow')
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
width: calc(100% + 6px)
|
||||
|
||||
&:before
|
||||
background-color: $activeColor
|
||||
theme('background-color', '$activeColor')
|
||||
border-top-left-radius: 7px
|
||||
border-bottom-left-radius: 7px
|
||||
content: ''
|
||||
@ -30,16 +30,16 @@
|
||||
opacity: 1
|
||||
|
||||
.lesionRowSidebar
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.rowOptions
|
||||
height: 35px
|
||||
visibility: visible
|
||||
|
||||
&.response-status .lesionRowSidebar .response-status-icon
|
||||
background-color: $defaultColor
|
||||
theme('background-color', '$defaultColor')
|
||||
theme('color', '$uiGray')
|
||||
border-radius: 11px
|
||||
color: $uiGray
|
||||
font-size: 12px
|
||||
font-weight: 700
|
||||
height: 21px
|
||||
@ -49,8 +49,8 @@
|
||||
width: 21px
|
||||
|
||||
&.warning .lesionRowSidebar
|
||||
color: $textPrimaryColor
|
||||
background-color: $uiYellow
|
||||
theme('background-color', '$uiYellow')
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
.warning-icon, svg
|
||||
width: 22px
|
||||
@ -60,31 +60,31 @@
|
||||
margin: 7px auto 0
|
||||
|
||||
svg
|
||||
fill: $textPrimaryColor
|
||||
theme('fill', '$textPrimaryColor')
|
||||
|
||||
.rowOptions
|
||||
background-color: $uiGrayDarker
|
||||
theme('background-color', '$uiGrayDarker')
|
||||
height: 0
|
||||
overflow: hidden
|
||||
transition(all 0.3s ease)
|
||||
visibility: hidden
|
||||
|
||||
.rowAction
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
line-height: 35px
|
||||
transition(all 0.3s ease)
|
||||
|
||||
&:hover, &:active
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
svg
|
||||
fill: $textPrimaryColor
|
||||
stroke: $textPrimaryColor
|
||||
theme('fill', '$textPrimaryColor')
|
||||
theme('stroke', '$textPrimaryColor')
|
||||
|
||||
svg
|
||||
fill: $defaultColor
|
||||
stroke: $defaultColor
|
||||
theme('fill', '$defaultColor')
|
||||
theme('stroke', '$defaultColor')
|
||||
transition(all 0.3s ease)
|
||||
|
||||
&.edit-icon
|
||||
@ -96,8 +96,8 @@
|
||||
height: 11px
|
||||
|
||||
.lesionRowSidebar
|
||||
background: $uiGray
|
||||
color: $textSecondaryColor
|
||||
theme('background', '$uiGray')
|
||||
theme('color', '$textSecondaryColor')
|
||||
cursor: pointer
|
||||
flex: 1
|
||||
max-width: 30px
|
||||
@ -120,7 +120,7 @@
|
||||
.location
|
||||
font-weight: 400
|
||||
font-size: 14px
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
height: 30px
|
||||
line-height: 30px
|
||||
margin-left: -2px
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
@import "{design}/app"
|
||||
|
||||
.lesionTableTimepointCell
|
||||
border-left: $uiBorderThickness $uiBorderColor solid
|
||||
color: $textPrimaryColor
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
theme('color', '$textPrimaryColor')
|
||||
padding: 0 10px
|
||||
|
||||
@ -5,18 +5,18 @@
|
||||
justify-content: space-around
|
||||
|
||||
div
|
||||
border-left: $uiBorderColor $uiBorderThickness solid
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
font-weight: 400
|
||||
padding-left: 12px
|
||||
text-align: left
|
||||
|
||||
.timepointName
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 12px
|
||||
line-height: 12px
|
||||
|
||||
.timepointDate
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
font-size: 14px
|
||||
line-height: 20px
|
||||
padding-bottom: 6px
|
||||
|
||||
@ -38,4 +38,5 @@
|
||||
{{ >lastLoginModal }}
|
||||
{{ >studyContextMenu }}
|
||||
{{ >progressDialog}}
|
||||
{{ >viewSeriesDetailsModal }}
|
||||
</template>
|
||||
|
||||
@ -9,8 +9,8 @@ $expandedHeight = 160px
|
||||
|
||||
.topBar
|
||||
height: $topBarHeight
|
||||
color: $textPrimaryColor
|
||||
background-color: $primaryBackgroundColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
transition(all 0.5s ease)
|
||||
|
||||
.brandSection
|
||||
@ -26,14 +26,14 @@ $expandedHeight = 160px
|
||||
display: inline-block
|
||||
font-family: $logoFontFamily
|
||||
font-weight: $logoFontWeight
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
line-height: 30px
|
||||
|
||||
.studyListLinkSection
|
||||
border-left: $uiBorderThickness solid $uiBorderColor;
|
||||
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
|
||||
.btn
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
cursor: pointer
|
||||
font-size: 13px
|
||||
font-weight: 500
|
||||
@ -41,10 +41,10 @@ $expandedHeight = 160px
|
||||
margin-top: 3px
|
||||
|
||||
&:hover
|
||||
color: $hoverColor
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
|
||||
&.studyList
|
||||
background-color: rgba(21, 25, 30, 0.7)
|
||||
@ -75,5 +75,5 @@ $expandedHeight = 160px
|
||||
.tab-pane
|
||||
.viewerContainer
|
||||
.loadingTextDiv
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 30px
|
||||
|
||||
@ -24,7 +24,10 @@
|
||||
Remove Association
|
||||
</a>
|
||||
<hr/>
|
||||
<a class="disabled">View Series Details</a>
|
||||
<a id="viewSeriesDetails" type="button"
|
||||
title="View Series Details">
|
||||
View Series Details
|
||||
</a>
|
||||
<a class="disabled">Anonymize</a>
|
||||
<a class="disabled">Send</a>
|
||||
<hr/>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<template name="measureFlow">
|
||||
<div class="measure-flow {{instance.state.get}}" style="position:fixed; top:200px; left:400px">
|
||||
<div class="measure-flow {{#if this.treeColumns}}tree-columns{{/if}} {{instance.state.get}}" style="position:fixed; top:200px; left:400px">
|
||||
<button class="btn-add">Add label</button>
|
||||
{{#if eq instance.state.get 'selected'}}
|
||||
<div class="tree-leaf">
|
||||
<i class="icon-check"></i>
|
||||
<span>{{instance.value.label}}</span>
|
||||
{{#if instance.descriptionEdit.get}}
|
||||
<div class="description clearfix">
|
||||
|
||||
@ -55,6 +55,7 @@ Template.measureFlow.onCreated(() => {
|
||||
}];
|
||||
|
||||
const items = [
|
||||
'Abdomen/Chest Wall',
|
||||
'Adrenal',
|
||||
'Bladder',
|
||||
'Bone',
|
||||
@ -68,9 +69,10 @@ Template.measureFlow.onCreated(() => {
|
||||
'Liver',
|
||||
'Lung',
|
||||
'Lymph Node',
|
||||
'Mediastinum/Hilum',
|
||||
'Muscle',
|
||||
'Neck',
|
||||
'Other: Soft Tissue',
|
||||
'Other Soft Tissue',
|
||||
'Ovary',
|
||||
'Pancreas',
|
||||
'Pelvis',
|
||||
@ -90,6 +92,25 @@ Template.measureFlow.onCreated(() => {
|
||||
value: item
|
||||
});
|
||||
});
|
||||
|
||||
const commonItems = [
|
||||
'Abdomen/Chest Wall',
|
||||
'Lung',
|
||||
'Lymph Node',
|
||||
'Liver',
|
||||
'Mediastinum/Hilum',
|
||||
'Pelvis',
|
||||
'Peritoneum/Omentum',
|
||||
'Retroperitoneum'
|
||||
];
|
||||
|
||||
instance.commonItems = [];
|
||||
_.each(commonItems, item => {
|
||||
instance.commonItems.push({
|
||||
label: item,
|
||||
value: item
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Template.measureFlow.onRendered(() => {
|
||||
@ -116,9 +137,12 @@ Template.measureFlow.events({
|
||||
const data = {
|
||||
key: 'label',
|
||||
items: instance.items,
|
||||
commonItems: instance.commonItems,
|
||||
hideCommon: instance.data.hideCommon,
|
||||
label: 'Assign label',
|
||||
searchPlaceholder: 'Search labels',
|
||||
storageKey: 'measureLabelCommon',
|
||||
treeColumns: instance.data.treeColumns,
|
||||
position
|
||||
};
|
||||
|
||||
@ -206,14 +230,14 @@ Template.measureFlow.events({
|
||||
// Change the measure flow state to selected
|
||||
instance.state.set('selected');
|
||||
|
||||
// Get the clicked label window offset
|
||||
const labelOffset = $label.offset();
|
||||
|
||||
// Wait for the DOM re-rendering
|
||||
Tracker.afterFlush(() => {
|
||||
// Get the measure flow div
|
||||
const $measureFlow = instance.$('.measure-flow');
|
||||
|
||||
// Get the clicked label window offset
|
||||
const labelOffset = $label.offset();
|
||||
|
||||
// Subtract the label box shadow height from the label's position
|
||||
labelOffset.top -= 10;
|
||||
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
opacity: 0
|
||||
|
||||
.btn-add
|
||||
background-color: $activeColor
|
||||
border: 2px solid $uiBorderColor
|
||||
theme('color', '$textColorActive')
|
||||
theme('background-color', '$activeColor')
|
||||
theme('border', '2px solid $uiBorderColor')
|
||||
border-radius: 14px
|
||||
color: $textColorActive
|
||||
cursor: pointer
|
||||
font-weight: bold
|
||||
height: 24px
|
||||
@ -26,14 +26,13 @@
|
||||
transition(opacity 0.3s ease)
|
||||
white-space: nowrap
|
||||
|
||||
// / {selector()}
|
||||
// color: $themes['tide']['uiYellow'] !important
|
||||
|
||||
.select-tree-root>.tree-content
|
||||
width: 213px
|
||||
|
||||
&>.tree-options
|
||||
margin-right: -17px
|
||||
max-height: 250px
|
||||
overflow-x: hidden
|
||||
overflow-y: scroll
|
||||
position: relative
|
||||
z-index: 2
|
||||
|
||||
@ -43,22 +42,11 @@
|
||||
&>.tree-leaf
|
||||
position: relative
|
||||
|
||||
&:before
|
||||
animateZoomIn()
|
||||
background-color: $activeColor
|
||||
border-radius: 20px
|
||||
color: $uiGray
|
||||
content: '\f00c'
|
||||
display: block
|
||||
font-family: FontAwesome
|
||||
font-size: 24px
|
||||
height: 40px
|
||||
.icon-check
|
||||
theme('background-color', '$activeColor')
|
||||
left: -46px
|
||||
line-height: 40px
|
||||
position: absolute
|
||||
text-align: center
|
||||
top: 3px
|
||||
width: 40px
|
||||
|
||||
span
|
||||
background: white
|
||||
@ -82,10 +70,10 @@
|
||||
animateFadeOut()
|
||||
|
||||
button
|
||||
theme('border', '1px solid $uiBorderColor')
|
||||
theme('color', '$textPrimaryColor')
|
||||
background-color: transparent
|
||||
border-radius: 16px
|
||||
border: 1px solid $uiBorderColor
|
||||
color: $textPrimaryColor
|
||||
font-weight: normal
|
||||
height: 31px
|
||||
line-height: 31px
|
||||
@ -120,3 +108,80 @@
|
||||
|
||||
span
|
||||
display: block
|
||||
|
||||
&.tree-columns
|
||||
|
||||
.select-tree-root
|
||||
|
||||
&.interacted .select-tree-common .content
|
||||
animation-name: none
|
||||
|
||||
&.selected .select-tree-common .content
|
||||
animation-name: selectTreeCommonCloseLeft
|
||||
|
||||
.tree-search
|
||||
input, i
|
||||
display: none
|
||||
|
||||
.select-tree-common
|
||||
padding-left: 0
|
||||
padding-right: 6px
|
||||
right: auto
|
||||
left: 0
|
||||
width: 33.333333333333%
|
||||
|
||||
&>.tree-content
|
||||
transform-origin(0% 50%)
|
||||
width: 426px
|
||||
|
||||
.select-tree-common .content
|
||||
right: -100%
|
||||
|
||||
&.started .select-tree-common .content
|
||||
right: 6px
|
||||
|
||||
&.interacted .select-tree-common .content
|
||||
animation-name: selectTreeCommonCloseRight
|
||||
|
||||
.tree-inputs>label
|
||||
float: left
|
||||
width: 50%
|
||||
|
||||
@keyframes selectTreeCommonCloseRight {
|
||||
from {
|
||||
height: 37px
|
||||
display: table
|
||||
right: 6px
|
||||
opacity: 1
|
||||
visibility: visible
|
||||
}
|
||||
to {
|
||||
height: 100%
|
||||
right: -100%
|
||||
opacity: 0
|
||||
visibility: hidden
|
||||
width: calc(100% - 6px)
|
||||
}
|
||||
}
|
||||
|
||||
.icon-check
|
||||
background-color: white
|
||||
border-radius: 20px
|
||||
display: block
|
||||
height: 40px
|
||||
overflow: hidden
|
||||
position: relative
|
||||
width: 40px
|
||||
|
||||
&:before
|
||||
border: 2px solid black
|
||||
border-left-width: 0
|
||||
border-top-width: 0
|
||||
content: ''
|
||||
display: block
|
||||
height: 18px
|
||||
left: 15px
|
||||
position: absolute
|
||||
top: 9px
|
||||
transform(rotate(45deg))
|
||||
width: 9px
|
||||
|
||||
@ -11,12 +11,12 @@ $circleSize = 46px
|
||||
|
||||
#svg circle
|
||||
stroke-dashoffset: 0
|
||||
stroke: $uiBorderColorDark
|
||||
theme('stroke', '$uiBorderColorDark')
|
||||
stroke-width: 3px
|
||||
vendorize(transition, stroke-dashoffset 1s linear)
|
||||
|
||||
#svg #bar
|
||||
stroke: $activeColor
|
||||
theme('stroke', '$activeColor')
|
||||
vendorize(transform, rotate(270deg))
|
||||
vendorize(transform-origin, center center)
|
||||
|
||||
@ -28,14 +28,14 @@ $circleSize = 46px
|
||||
font-weight: 700
|
||||
font-size: 17px
|
||||
text-align: center
|
||||
color: $activeColor
|
||||
theme('color', '$activeColor')
|
||||
top: 0
|
||||
|
||||
svg
|
||||
fill: $activeColor
|
||||
theme('fill', '$activeColor')
|
||||
left: 50%
|
||||
position: absolute
|
||||
stroke: $activeColor
|
||||
theme('stroke', '$activeColor')
|
||||
top: 50%
|
||||
transform(translateX(-50%) translateY(-50%))
|
||||
|
||||
|
||||
@ -1,30 +1,27 @@
|
||||
<template name="serverInformationDicomWeb">
|
||||
<div class="row">
|
||||
{{>serverInformationFormField name="wadoUriRoot" label="WADO URI root"}}
|
||||
{{>serverInformationFormField name="wadoUriRootNOTE" label="WADO URI root note"}}
|
||||
{{>serverInformationFormField name="wadoRoot" label="WADO root"}}
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label class="wrapper">
|
||||
<strong>Image rendering</strong>
|
||||
<select name="imageRendering" class="form-control">
|
||||
<option>Select</option>
|
||||
<option value="wadouri">WADO URI</option>
|
||||
<option value="orthanc">ORTHANC</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
{{>inputText labelClass='form-group' key='wadoUriRoot'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputText labelClass='form-group' key='wadoUriRootNOTE'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputText labelClass='form-group' key='wadoRoot'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputSelect labelClass='form-group' key='imageRendering' hideSearch=true
|
||||
options=(clone placeholder='Select an option')}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputText labelClass='form-group' key='qidoRoot'}}
|
||||
</div>
|
||||
{{>serverInformationFormField name="qidoRoot" label="QIDO root"}}
|
||||
<div class="col-lg-6">
|
||||
<strong>QIDO options</strong>
|
||||
<div class="form-group">
|
||||
<div class="form-control">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="qidoSupportsIncludeField">
|
||||
<span>QIDO supports including fields</span>
|
||||
</label>
|
||||
{{>inputCheckbox key='qidoSupportsIncludeField'}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -32,32 +29,25 @@
|
||||
</div>
|
||||
<hr>
|
||||
<h4>Request options</h4>
|
||||
<div class="row">
|
||||
{{>serverInformationFormField name="requestOptions.auth" label="Authentication"}}
|
||||
{{#group class='row' key='requestOptions'}}
|
||||
<div class="col-lg-6">
|
||||
{{>inputText labelClass='form-group' key='auth'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<strong>Logging options</strong>
|
||||
<div class="form-group">
|
||||
<div class="form-control clearfix">
|
||||
<div class="checkbox pull-left">
|
||||
<label>
|
||||
<input type="checkbox" name="requestOptions.logRequests">
|
||||
<span>Requests</span>
|
||||
</label>
|
||||
{{>inputCheckbox key='logRequests'}}
|
||||
</div>
|
||||
<div class="checkbox pull-left">
|
||||
<label>
|
||||
<input type="checkbox" name="requestOptions.logResponses">
|
||||
<span>Responses</span>
|
||||
</label>
|
||||
{{>inputCheckbox key='logResponses'}}
|
||||
</div>
|
||||
<div class="checkbox pull-left">
|
||||
<label>
|
||||
<input type="checkbox" name="requestOptions.logTiming">
|
||||
<span>Timing</span>
|
||||
</label>
|
||||
{{>inputCheckbox key='logTiming'}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/group}}
|
||||
</template>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
Template.serverInformationDicomWeb.onRendered(function() {
|
||||
var instance = Template.instance();
|
||||
Template.serverInformationDicomWeb.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
instance.autorun(function() {
|
||||
var mode = instance.data.mode.get();
|
||||
const mode = instance.data.mode.get();
|
||||
if (mode === 'edit') {
|
||||
var data = instance.data.currentItem.get();
|
||||
FormUtils.setFormData(instance.data.$form, data);
|
||||
const data = instance.data.currentItem.get();
|
||||
instance.data.form.value(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,43 +1,45 @@
|
||||
<template name="serverInformationDimse">
|
||||
<div class="panel panel-default panel-body">
|
||||
<div class="clearfix">
|
||||
<h4 class="pull-left">Peer list</h4>
|
||||
<h4 class="pull-left">Peer List</h4>
|
||||
<button class="btn btn-primary pull-right js-new-peer">New peer</button>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
{{#group class='row' key='peers' arrayValues=true}}
|
||||
{{#each peer in instance.peers.get}}
|
||||
<div class="col-lg-6">
|
||||
{{#group class='col-lg-6'}}
|
||||
<div class="panel panel-default panel-body">
|
||||
<div class="row">
|
||||
{{>serverInformationFormField name=(concat "peers[]." @index ".aeTitle") label="AE title"}}
|
||||
{{>serverInformationFormField name=(concat "peers[]." @index ".hostAE") label="AE host"}}
|
||||
{{>serverInformationFormField name=(concat "peers[]." @index ".host") label="Host"}}
|
||||
{{>serverInformationFormField name=(concat "peers[]." @index ".port") label="Port"}}
|
||||
<div class="col-lg-6">
|
||||
{{>inputText class='form-control' key='aeTitle'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputText class='form-control' key='hostAE'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputText class='form-control' key='host'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
{{>inputText class='form-control' key='port'}}
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<strong>Settings</strong>
|
||||
<div class="form-group">
|
||||
<div class="form-control clearfix">
|
||||
<div class="checkbox pull-left">
|
||||
<label>
|
||||
<input type="checkbox" name="peers[].{{@index}}.default">
|
||||
<span>Default</span>
|
||||
</label>
|
||||
{{>inputCheckbox key='default'}}
|
||||
</div>
|
||||
<div class="checkbox pull-left">
|
||||
<label>
|
||||
<input type="checkbox" name="peers[].{{@index}}.server">
|
||||
<span>Server</span>
|
||||
</label>
|
||||
{{>inputCheckbox key='server'}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/group}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/group}}
|
||||
</div>
|
||||
<hr>
|
||||
</template>
|
||||
|
||||
@ -1,29 +1,29 @@
|
||||
Template.serverInformationDimse.onCreated(function() {
|
||||
var instance = Template.instance();
|
||||
Template.serverInformationDimse.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
instance.peers = new ReactiveVar([]);
|
||||
instance.autorun(function() {
|
||||
var currentItem = instance.data.currentItem.get();
|
||||
instance.autorun(() => {
|
||||
const currentItem = instance.data.currentItem.get();
|
||||
if (currentItem) {
|
||||
instance.peers.set(currentItem.peers || []);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.serverInformationDimse.onRendered(function() {
|
||||
var instance = Template.instance();
|
||||
instance.autorun(function() {
|
||||
var mode = instance.data.mode.get();
|
||||
Template.serverInformationDimse.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
instance.autorun(() => {
|
||||
const mode = instance.data.mode.get();
|
||||
if (mode === 'edit') {
|
||||
var data = instance.data.currentItem.get();
|
||||
FormUtils.setFormData(instance.data.$form, data);
|
||||
const data = instance.data.currentItem.get();
|
||||
instance.data.form.value(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.serverInformationDimse.events({
|
||||
'click .js-new-peer': function(event, instance) {
|
||||
'click .js-new-peer'(event, instance) {
|
||||
event.preventDefault();
|
||||
var peers = instance.peers.get();
|
||||
const peers = instance.peers.get();
|
||||
peers.push({});
|
||||
instance.peers.set(peers);
|
||||
}
|
||||
|
||||
@ -1,33 +1,21 @@
|
||||
<template name="serverInformationForm">
|
||||
<form class="server-information-form">
|
||||
<input type="hidden" name="_id">
|
||||
{{#form class='server-information-form' schema=instance.currentSchema}}
|
||||
{{>inputHidden key='_id'}}
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label class="wrapper">
|
||||
<strong>Server Name</strong>
|
||||
<input type="text" name="name" class="form-control">
|
||||
</label>
|
||||
</div>
|
||||
{{>inputText labelClass='form-group' key='name'}}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label class="wrapper">
|
||||
<strong>Server Type</strong>
|
||||
<select name="type" class="form-control js-server-type">
|
||||
<option>Select</option>
|
||||
<option value="dicomWeb">DICOM Web</option>
|
||||
<option value="dimse">DIMSE</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
{{>inputSelect labelClass='form-group' key='type'
|
||||
hideSearch=true disabled=(eq this.mode.get 'edit')
|
||||
options=(clone placeholder='Choose a server type')}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{#if eq this.serverType.get "dicomWeb"}}
|
||||
{{#if eq this.serverType.get 'dicomWeb'}}
|
||||
{{>serverInformationDicomWeb this}}
|
||||
{{/if}}
|
||||
{{#if eq this.serverType.get "dimse"}}
|
||||
{{#if eq this.serverType.get 'dimse'}}
|
||||
{{>serverInformationDimse this}}
|
||||
{{/if}}
|
||||
{{#if this.serverType.get}}
|
||||
@ -35,5 +23,5 @@
|
||||
<input type="submit" class="btn btn-primary" value="Save">
|
||||
</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/form}}
|
||||
</template>
|
||||
|
||||
@ -1,24 +1,68 @@
|
||||
Template.serverInformationForm.onRendered(function() {
|
||||
var instance = Template.instance();
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { DICOMWebServer as dicomSchema } from 'meteor/worklist/both/schema';
|
||||
import { DIMSEServer as dimseSchema } from 'meteor/worklist/both/schema';
|
||||
|
||||
instance.data.$form = instance.$('form');
|
||||
instance.autorun(function() {
|
||||
var mode = instance.data.mode.get();
|
||||
Template.serverInformationForm.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.currentSchema = new ReactiveVar(dicomSchema);
|
||||
});
|
||||
|
||||
Template.serverInformationForm.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.data.$form = instance.$('form:first');
|
||||
instance.data.form = instance.data.$form.data('component');
|
||||
|
||||
// Handle the server type
|
||||
instance.autorun(() => {
|
||||
// Get the server type component
|
||||
const typeComponent = instance.$('[data-key=type] :input').data('component');
|
||||
|
||||
// Run this computation every time the user change the server type
|
||||
typeComponent.depend();
|
||||
|
||||
// Get the current server type value
|
||||
const type = typeComponent.value();
|
||||
|
||||
// Set the serverType reactive value
|
||||
instance.data.serverType.set(type);
|
||||
|
||||
// Change the schema based on the selected server type
|
||||
if (type === 'dimse') {
|
||||
instance.currentSchema.set(dimseSchema);
|
||||
} else {
|
||||
instance.currentSchema.set(dicomSchema);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle the form mode (edit or add)
|
||||
instance.autorun(() => {
|
||||
const mode = instance.data.mode.get();
|
||||
|
||||
// Check if it is on edit mode and load the saved data
|
||||
if (mode === 'edit') {
|
||||
var data = instance.data.currentItem.get();
|
||||
FormUtils.setFormData(instance.data.$form, data);
|
||||
const data = instance.data.currentItem.get();
|
||||
instance.data.form.value(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.serverInformationForm.events({
|
||||
'change .js-server-type': function(event, instance) {
|
||||
var value = $(event.currentTarget).val();
|
||||
instance.data.serverType.set(value);
|
||||
},
|
||||
submit: function(event, instance) {
|
||||
submit(event, instance) {
|
||||
event.preventDefault();
|
||||
var formData = FormUtils.getFormData(instance.data.$form);
|
||||
|
||||
// Stop here if the form validation fails
|
||||
if (!instance.data.form.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current form data
|
||||
const formData = instance.data.form.value();
|
||||
|
||||
// Call the save method
|
||||
Meteor.call('serverSave', formData, function(error) {
|
||||
if (error) {
|
||||
// TODO: check for errors: not-authorized, data-write
|
||||
|
||||
@ -15,7 +15,7 @@ $seriesSpacing = 2px
|
||||
transform(translateX(-50%))
|
||||
|
||||
&.left
|
||||
border-right: 1px solid $uiBorderColor
|
||||
theme('border-right', '1px solid $uiBorderColor')
|
||||
right: 50%
|
||||
|
||||
&.right
|
||||
@ -26,7 +26,7 @@ $seriesSpacing = 2px
|
||||
z-index: 3
|
||||
|
||||
&:before
|
||||
background-color: $primaryBackgroundColor
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
bottom: 0
|
||||
content: ''
|
||||
left: 0
|
||||
@ -98,10 +98,10 @@ $seriesSpacing = 2px
|
||||
.studyTimepointBrowser
|
||||
background-color: transparent
|
||||
.studyTimepointStudy.active .studyModality
|
||||
box-shadow: inset 0 0 0 3px $activeColor
|
||||
theme('box-shadow', 'inset 0 0 0 3px $activeColor')
|
||||
.studyBox
|
||||
background-color: $uiGrayDark
|
||||
border: solid 1px $activeColor
|
||||
theme('background-color', '$uiGrayDark')
|
||||
theme('border', 'solid 1px $activeColor')
|
||||
border-radius: 11px
|
||||
display: block
|
||||
height: $switchSize
|
||||
@ -113,7 +113,7 @@ $seriesSpacing = 2px
|
||||
width: $switchSize + $seriesSpacing
|
||||
|
||||
.seriesItem
|
||||
background-color: $boxBackgroundColorDark
|
||||
theme('background-color', '$boxBackgroundColor')Dark
|
||||
border-radius: 3px
|
||||
height: 15px
|
||||
margin: $seriesSpacing
|
||||
@ -121,17 +121,17 @@ $seriesSpacing = 2px
|
||||
|
||||
&.count
|
||||
background-color: transparent
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
font-size: 12px
|
||||
font-weight: 500
|
||||
line-height: 17px
|
||||
text-align: center
|
||||
|
||||
&.active
|
||||
background-color: $activeColor
|
||||
theme('background-color', '$activeColor')
|
||||
|
||||
.label
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
display: block
|
||||
font-size: 12px
|
||||
font-weight: 300
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
$timepointButtonHeight = 55px
|
||||
|
||||
.studyTimepointBrowser
|
||||
background-color: $primaryBackgroundColor
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
float: left
|
||||
height: 100%
|
||||
position: relative
|
||||
width: 100%
|
||||
|
||||
.timepointButtonContainer
|
||||
background-color: $primaryBackgroundColor
|
||||
border-bottom: 1px solid $uiBorderColor
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
theme('border-bottom', '1px solid $uiBorderColor')
|
||||
display: none
|
||||
height: $timepointButtonHeight
|
||||
left: 10px
|
||||
@ -38,7 +38,7 @@ $timepointButtonHeight = 55px
|
||||
transform: rotateX(180deg)
|
||||
.timepointFollowupTitle
|
||||
font-size: 14px
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
text-transform: uppercase
|
||||
|
||||
.timepointHeader
|
||||
@ -50,7 +50,7 @@ $timepointButtonHeight = 55px
|
||||
.timepointFollowupTitle
|
||||
.timepointDate
|
||||
.timepointModalities
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
transition($sidebarTransition)
|
||||
|
||||
&:hover
|
||||
@ -59,7 +59,7 @@ $timepointButtonHeight = 55px
|
||||
.expandIcon i
|
||||
.timepointDate
|
||||
.timepointModalities
|
||||
color: $textPrimaryColor !important
|
||||
theme('color', '$textPrimaryColor') !important
|
||||
|
||||
.timepointDetails
|
||||
.timepointModalities
|
||||
@ -70,10 +70,10 @@ $timepointButtonHeight = 55px
|
||||
overflow: hidden
|
||||
|
||||
.expandIcon i
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
|
||||
.timepointFollowupTitle
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
padding-top: 2px
|
||||
|
||||
.studyTimepointScrollArea
|
||||
@ -91,7 +91,7 @@ $timepointButtonHeight = 55px
|
||||
margin-right: 16px
|
||||
|
||||
.studySidebarTimepoint .thumbnailEntry.active:before
|
||||
background-color: $activeColor
|
||||
theme('background-color', '$activeColor')
|
||||
border-top-right-radius: 7px
|
||||
border-bottom-right-radius: 7px
|
||||
content: ''
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
$boxBorderColor = transparent
|
||||
$boxHoverBackgroundColor = #14191E
|
||||
$boxHoverBorderColor = #2d4660
|
||||
$boxActiveBackgroundColor = $activeColor
|
||||
$boxActiveTextColor = $primaryBackgroundColor
|
||||
$boxActiveBorderColor = #131D29
|
||||
$boxWidth = 50px
|
||||
$borderThickness = 2px
|
||||
@ -41,11 +39,11 @@ $spacerY = 12px
|
||||
&.active
|
||||
.studyModality
|
||||
.studyModalityBox
|
||||
color: $boxActiveTextColor
|
||||
theme('color', '$primaryBackgroundColor')
|
||||
&
|
||||
&:before
|
||||
&:after
|
||||
background-color: $boxActiveBackgroundColor
|
||||
theme('background-color', '$activeColor')
|
||||
border-color: $boxActiveBorderColor
|
||||
|
||||
&:not(.active) .studyTimepointThumbnails
|
||||
@ -69,10 +67,10 @@ $spacerY = 12px
|
||||
border-color: $boxHoverBorderColor
|
||||
|
||||
&.additional
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
|
||||
&.additional
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
font-size: 16px
|
||||
font-weight: normal
|
||||
height: 91px
|
||||
@ -89,13 +87,13 @@ $spacerY = 12px
|
||||
top: $spacerY
|
||||
.studyDate
|
||||
margin-top: 8px
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
.studyDescription
|
||||
margin-top: 8px
|
||||
color: $textPrimaryColor
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
.studyModalityBox
|
||||
color: $textSecondaryColor
|
||||
theme('color', '$textSecondaryColor')
|
||||
line-height: $boxWidth
|
||||
margin-left: $nestingMargin * 2
|
||||
margin-top: $nestingMargin * 2
|
||||
@ -109,8 +107,8 @@ $spacerY = 12px
|
||||
&
|
||||
&:before
|
||||
&:after
|
||||
background-color: $boxBackgroundColor
|
||||
border: $borderThickness solid $primaryBackgroundColor
|
||||
theme('border', '$borderThickness solid $primaryBackgroundColor')
|
||||
theme('background-color', '$boxBackgroundColor')
|
||||
border-radius: $boxBorderRadius
|
||||
height: $boxWidth + ($borderThickness * 2)
|
||||
transition($sidebarTransition)
|
||||
|
||||
@ -53,7 +53,10 @@ Template.toolbarSection.helpers({
|
||||
},
|
||||
|
||||
toolbarButtons() {
|
||||
var buttonData = [];
|
||||
// Check if the measure tools shall be disabled
|
||||
const isMesureDisabled = !Template.instance().data.timepointApi.currentTimepointId;
|
||||
const buttonData = [];
|
||||
|
||||
buttonData.push({
|
||||
id: 'zoom',
|
||||
title: 'Zoom',
|
||||
@ -86,14 +89,16 @@ Template.toolbarSection.helpers({
|
||||
id: 'bidirectional',
|
||||
title: 'Target',
|
||||
classes: 'imageViewerTool rm-l-3',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-target'
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-target',
|
||||
disabled: isMesureDisabled
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'nonTarget',
|
||||
title: 'Non-Target',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-non-target'
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-non-target',
|
||||
disabled: isMesureDisabled
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
@ -107,28 +112,33 @@ Template.toolbarSection.helpers({
|
||||
},
|
||||
|
||||
extraToolbarButtons() {
|
||||
let buttonData = [];
|
||||
// Check if the measure tools shall be disabled
|
||||
const isMesureDisabled = !Template.instance().data.timepointApi.currentTimepointId;
|
||||
const buttonData = [];
|
||||
|
||||
// TODO: Get real icons for CR / UN / EX
|
||||
buttonData.push({
|
||||
id: 'crTool',
|
||||
title: 'CR Tool',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp',
|
||||
disabled: isMesureDisabled
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'unTool',
|
||||
title: 'UN Tool',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp',
|
||||
disabled: isMesureDisabled
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'exTool',
|
||||
title: 'EX Tool',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
svgLink: '/packages/viewerbase/assets/icons.svg#icon-tools-measure-temp',
|
||||
disabled: isMesureDisabled
|
||||
});
|
||||
|
||||
return buttonData;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import "{design}/app"
|
||||
|
||||
.toolbarSection
|
||||
border-bottom: $uiBorderColor $uiBorderThickness solid
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
flex: 0 0 auto
|
||||
height: $toolbarHeight
|
||||
overflow: hidden
|
||||
@ -14,11 +14,11 @@
|
||||
height: $toolbarHeight + $toolbarDrawerHeight
|
||||
|
||||
.toolbarSectionEntry
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
display: inline-block
|
||||
fill: $defaultColor
|
||||
theme('fill', '$defaultColor')
|
||||
margin-top: 3px
|
||||
min-width: 30px
|
||||
stroke: $defaultColor
|
||||
text-align: center
|
||||
theme('stroke', '$defaultColor')
|
||||
text-align: center
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { Session } from 'meteor/session';
|
||||
|
||||
// Display the last login modal as default
|
||||
Session.setDefault('displayLastLoginModal', true);
|
||||
|
||||
Template.userAccountMenu.helpers({
|
||||
name: function() {
|
||||
var nameSplit = Meteor.user().profile.fullName.split(' ');
|
||||
@ -29,68 +36,87 @@ Template.userAccountMenu.events({
|
||||
$('#serverInformationModal').modal('show');
|
||||
},
|
||||
'click #logoutButton': function() {
|
||||
// Remove reviewers info for the user
|
||||
Meteor.call('removeUserFromReviewers', Meteor.userId());
|
||||
|
||||
Meteor.logout(function() {
|
||||
Router.go('/entrySignIn');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.userAccountMenu.onRendered(function() {
|
||||
var oldUserId;
|
||||
var lastLoginModalInterval;
|
||||
Template.userAccountMenu.onCreated(function userAccountMenuCreated() {
|
||||
const instance = Template.instance();
|
||||
|
||||
this.autorun(function() {
|
||||
// Hook login/logout
|
||||
var user = Meteor.user();
|
||||
if (!user) {
|
||||
// Create reactive last login date
|
||||
instance.lastLoginDate = new ReactiveVar();
|
||||
|
||||
// We need oldUser to remove Reviewers if the user logged out
|
||||
let oldUser;
|
||||
|
||||
// Get last login date
|
||||
Meteor.call('getPriorLoginDate', function(error, lastLoginDate){
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var newUserId = user._id;
|
||||
// Format the last login date
|
||||
const formattedLastLoginDate = moment(lastLoginDate).format("MMMM Do YYYY, HH:mm:ss A");
|
||||
|
||||
if (oldUserId === null && newUserId) {
|
||||
Session.set('showLastLoginModal', true);
|
||||
instance.lastLoginDate.set(formattedLastLoginDate);
|
||||
|
||||
// Log
|
||||
HipaaLogger.logEvent({
|
||||
eventType: 'init',
|
||||
userId: user._id,
|
||||
userName: user.fullName
|
||||
});
|
||||
});
|
||||
|
||||
} else if (newUserId === null && oldUserId) {
|
||||
// Set showLastLoginModal as null
|
||||
Session.set('showLastLoginModal', null);
|
||||
|
||||
// Destroy interval for last login modal
|
||||
Meteor.clearInterval(lastLoginModalInterval);
|
||||
console.log('The user logged out');
|
||||
|
||||
// Log
|
||||
// TODO: eventType is not defined for logout in hipaa-audit-log
|
||||
/*HipaaLogger.logEvent({
|
||||
eventType: 'logout',
|
||||
userId: oldUserId,
|
||||
userName: userName
|
||||
});*/
|
||||
|
||||
// Remove the user from Reviewers
|
||||
Meteor.call('removeUserFromReviewers', oldUserId);
|
||||
instance.autorun(function() {
|
||||
const lastLoginDate = instance.lastLoginDate.get();
|
||||
if (!lastLoginDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
oldUserId = Meteor.userId();
|
||||
// Hook login/logout
|
||||
var user = Meteor.user();
|
||||
if (!user) {
|
||||
// Display last login modal for the next login
|
||||
Session.setPersistent('displayLastLoginModal', true);
|
||||
|
||||
if (oldUser) {
|
||||
// Log Signout
|
||||
// TODO: eventType for logout is not defined
|
||||
// HipaaLogger.logEvent({
|
||||
// eventType: 'logout',
|
||||
// userId: oldUser._id,
|
||||
// userName: oldUser.profile.fullName
|
||||
// });
|
||||
|
||||
// Remove the user by oldUserId from Reviewers
|
||||
Meteor.call('removeUserFromReviewers', oldUser._id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Set oldUser
|
||||
oldUser = user;
|
||||
|
||||
// Trigger last login date popup
|
||||
if (Session.get('showLastLoginModal')) {
|
||||
Modal.show('lastLoginModal');
|
||||
|
||||
lastLoginModalInterval = Meteor.setInterval(function() {
|
||||
Modal.hide('lastLoginModal');
|
||||
Session.set('showLastLoginModal', null);
|
||||
}, 3000);
|
||||
if (!Session.get('displayLastLoginModal')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Displaye the modal
|
||||
Modal.show('lastLoginModal', {
|
||||
lastLoginDate: lastLoginDate
|
||||
});
|
||||
|
||||
// Hide the modal after 5sec
|
||||
Meteor.setTimeout(() => {
|
||||
Modal.hide('lastLoginModal');
|
||||
Session.setPersistent('displayLastLoginModal', false);
|
||||
}, 5000);
|
||||
|
||||
// Log signin
|
||||
HipaaLogger.logEvent({
|
||||
eventType: 'init',
|
||||
userId: user._id,
|
||||
userName: user.profile.fullName
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@ -5,7 +5,7 @@
|
||||
height: 100%
|
||||
|
||||
.dropdown-toggle
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
cursor: pointer
|
||||
font-size: 13px
|
||||
font-weight: 400
|
||||
@ -13,19 +13,19 @@
|
||||
text-decoration: none
|
||||
|
||||
.menuButton
|
||||
border-left: solid 1px $defaultColor
|
||||
theme('border-left', 'solid 1px $defaultColor')
|
||||
display: inline-block
|
||||
height: 18px
|
||||
padding: 0 8px
|
||||
|
||||
.fa
|
||||
color: $defaultColor
|
||||
theme('color', '$defaultColor')
|
||||
font-size: 17px
|
||||
line-height: 18px
|
||||
|
||||
.caret-down
|
||||
theme('color', '$uiLightGray')
|
||||
margin: 0 4px 4px 2px
|
||||
color: $uiLightGray
|
||||
|
||||
ul.dropdown-menu
|
||||
li
|
||||
|
||||
@ -19,4 +19,4 @@
|
||||
&:not(:last-child)
|
||||
.removable
|
||||
.imageViewerViewport
|
||||
border-right: $uiBorderThickness solid $uiBorderColor
|
||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
|
||||
@ -1,105 +0,0 @@
|
||||
class Form {
|
||||
|
||||
// Identify the element's type and get its value
|
||||
static getElementValue($element) {
|
||||
var type = $element.attr('type');
|
||||
var value;
|
||||
switch (type) {
|
||||
case 'checkbox':
|
||||
value = $element.is(':checked');
|
||||
break;
|
||||
default:
|
||||
value = $element.val();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
// Identify the element's type and get its value
|
||||
static setElementValue($element, value) {
|
||||
if (!$element.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var type = $element.attr('type');
|
||||
switch (type) {
|
||||
case 'checkbox':
|
||||
$element.prop('checked', !!value);
|
||||
break;
|
||||
default:
|
||||
$element.val(value);
|
||||
}
|
||||
$element.trigger('change');
|
||||
};
|
||||
|
||||
// Transforms a shallow object with keys separated by "." into a nested object
|
||||
static getNestedObject(shallowObject) {
|
||||
var nestedObject = {};
|
||||
for (var key in shallowObject) {
|
||||
var value = shallowObject[key];
|
||||
var propertyArray = key.split('.');
|
||||
var currentObject = nestedObject;
|
||||
while (propertyArray.length) {
|
||||
var currentProperty = propertyArray.shift();
|
||||
if (!propertyArray.length) {
|
||||
currentObject[currentProperty] = value;
|
||||
} else {
|
||||
if (!currentObject[currentProperty]) {
|
||||
currentObject[currentProperty] = {};
|
||||
}
|
||||
|
||||
currentObject = currentObject[currentProperty];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nestedObject;
|
||||
};
|
||||
|
||||
// Transforms a nested object into a shallowObject merging its keys with "." character
|
||||
static getShallowObject(nestedObject) {
|
||||
var shallowObject = {};
|
||||
var putValues = function(baseKey, nestedObject, resultObject) {
|
||||
for (var key in nestedObject) {
|
||||
var currentKey = baseKey ? baseKey + '.' + key : key;
|
||||
var currentValue = nestedObject[key];
|
||||
if (typeof currentValue === 'object') {
|
||||
if (currentValue instanceof Array) {
|
||||
currentKey += '[]';
|
||||
}
|
||||
|
||||
putValues(currentKey, currentValue, resultObject);
|
||||
} else {
|
||||
resultObject[currentKey] = currentValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
putValues('', nestedObject, shallowObject);
|
||||
return shallowObject;
|
||||
}
|
||||
|
||||
// Gets the nested data for the given form
|
||||
static getFormData($form) {
|
||||
var data = {};
|
||||
$form.find(':input[name]').each((index, element) => {
|
||||
var $element = $(element);
|
||||
var value = this.getElementValue($element);
|
||||
var name = $element.attr('name');
|
||||
data[name] = value;
|
||||
});
|
||||
return this.getNestedObject(data);
|
||||
}
|
||||
|
||||
// Sets the nested data in the given form
|
||||
static setFormData($form, data) {
|
||||
var shallowData = this.getShallowObject(data);
|
||||
for (var key in shallowData) {
|
||||
var value = shallowData[key];
|
||||
var $element = $form.find(':input[name="' + key + '"]');
|
||||
this.setElementValue($element, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FormUtils = Form;
|
||||
@ -58,9 +58,6 @@ Package.onUse(function(api) {
|
||||
|
||||
api.addFiles('client/tools.js', 'client');
|
||||
|
||||
// Utility classes
|
||||
api.addFiles('client/utils/form.js', 'client');
|
||||
|
||||
// UI Components
|
||||
api.addFiles('client/components/viewer/viewer.html', 'client');
|
||||
api.addFiles('client/components/viewer/viewer.styl', 'client');
|
||||
@ -101,6 +98,8 @@ Package.onUse(function(api) {
|
||||
api.addFiles('client/components/activeEntry/activeEntry.styl', 'client');
|
||||
api.addFiles('client/components/activeEntry/activeEntry.js', 'client');
|
||||
|
||||
api.addFiles('client/components/activeEntry/activeEntrySignIn/activeEntrySignIn.js', 'client');
|
||||
|
||||
api.addFiles('client/components/hipaaLogPage/hipaaLogPage.styl', 'client');
|
||||
api.addFiles('client/components/hipaaLogPage/hipaaLogPage.js', 'client');
|
||||
|
||||
@ -197,7 +196,6 @@ Package.onUse(function(api) {
|
||||
api.addFiles('client/components/confirmRemoveTimepointAssociation/confirmRemoveTimepointAssociation.js', 'client');
|
||||
|
||||
api.addFiles('client/components/lastLoginModal/lastLoginModal.html', 'client');
|
||||
api.addFiles('client/components/lastLoginModal/lastLoginModal.js', 'client');
|
||||
|
||||
api.addFiles('client/components/confirmDeleteDialog/confirmDeleteDialog.html', 'client');
|
||||
api.addFiles('client/components/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');
|
||||
@ -208,10 +206,11 @@ Package.onUse(function(api) {
|
||||
api.addFiles('client/components/emailVerification/emailVerification.js', 'client');
|
||||
|
||||
// Server functions
|
||||
api.addFiles('server/servers.js', 'server');
|
||||
api.addFiles('server/publications.js', 'server');
|
||||
api.addFiles('server/servers.js', 'server');
|
||||
api.addFiles('server/methods.js', [ 'server' ]);
|
||||
api.addFiles('server/reviewers.js', [ 'server' ]);
|
||||
api.addFiles('server/createDemoUser.js', [ 'server' ]);
|
||||
|
||||
// Both client and server functions
|
||||
api.addFiles('both/collections.js', [ 'client', 'server' ]);
|
||||
|
||||
39
Packages/lesiontracker/server/createDemoUser.js
Normal file
39
Packages/lesiontracker/server/createDemoUser.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
|
||||
|
||||
Meteor.startup(function() {
|
||||
const options = {
|
||||
email: 'demo@ohif.org',
|
||||
password: '12345678aA*',
|
||||
profile: {
|
||||
fullName: 'Demo User'
|
||||
}
|
||||
};
|
||||
|
||||
createDemoUser = function() {
|
||||
const user = Meteor.users.findOne({
|
||||
emails: {
|
||||
$elemMatch: {
|
||||
address: 'demo@ohif.org'
|
||||
}
|
||||
}
|
||||
});
|
||||
if (user) {
|
||||
return;
|
||||
}
|
||||
console.log('create user!');
|
||||
|
||||
// Create user
|
||||
const userId = Accounts.createUser(options);
|
||||
|
||||
if (!userId) {
|
||||
console.log('Demo user cannot be created');
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Create demo user
|
||||
createDemoUser();
|
||||
|
||||
});
|
||||
|
||||
@ -85,7 +85,13 @@ Meteor.methods({
|
||||
},
|
||||
|
||||
getPriorLoginDate: function() {
|
||||
return Meteor.users.findOne({_id: Meteor.userId()}, {fields: {priorLoginDate: 1}});
|
||||
return Meteor.users.findOne({
|
||||
_id: Meteor.userId()
|
||||
}, {
|
||||
fields: {
|
||||
priorLoginDate: 1
|
||||
}
|
||||
}).priorLoginDate;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -69,4 +69,4 @@ Meteor.methods({
|
||||
serverSave: serverSettings => ServersControl.save(serverSettings),
|
||||
serverSetActive: serverId => ServersControl.setActive(serverId),
|
||||
serverRemove: serverId => ServersControl.remove(serverId)
|
||||
});
|
||||
});
|
||||
|
||||
1
Packages/ohif-core/both/index.js
Normal file
1
Packages/ohif-core/both/index.js
Normal file
@ -0,0 +1 @@
|
||||
import './schema.js';
|
||||
34
Packages/ohif-core/both/schema.js
Normal file
34
Packages/ohif-core/both/schema.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
|
||||
|
||||
/*
|
||||
Extend the available options on schema definitions:
|
||||
|
||||
* valuesLabels: Used in conjunction with allowedValues to define the text
|
||||
label for each value (used on forms)
|
||||
|
||||
* textOptional: Used to allow empty strings
|
||||
|
||||
*/
|
||||
SimpleSchema.extendOptions({
|
||||
valuesLabels: Match.Optional([String]),
|
||||
textOptional: Match.Optional(Boolean)
|
||||
});
|
||||
|
||||
// Add default required validation for empty strings which can be bypassed
|
||||
// using textOptional=true definition
|
||||
SimpleSchema.addValidator(function() {
|
||||
if (
|
||||
this.definition.optional !== true &&
|
||||
this.definition.textOptional !== true &&
|
||||
this.value === ''
|
||||
) {
|
||||
return 'required';
|
||||
}
|
||||
});
|
||||
|
||||
// Including [label] for some messages
|
||||
SimpleSchema.messages({
|
||||
maxCount: '[label] can not have more than [maxCount] values',
|
||||
minCount: '[label] must have at least [minCount] values',
|
||||
notAllowed: '[label] has an invalid value: "[value]"'
|
||||
});
|
||||
@ -10,6 +10,7 @@ import './mixins/formItem.js';
|
||||
import './mixins/group.js';
|
||||
import './mixins/groupRadio.js';
|
||||
import './mixins/input.js';
|
||||
import './mixins/checkbox.js';
|
||||
import './mixins/schemaData.js';
|
||||
import './mixins/select.js';
|
||||
import './mixins/select2.js';
|
||||
|
||||
26
Packages/ohif-core/client/components/base/mixins/checkbox.js
Normal file
26
Packages/ohif-core/client/components/base/mixins/checkbox.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
/*
|
||||
* inputCheckbox: controls a checkbox input
|
||||
*/
|
||||
OHIF.mixins.checkbox = new OHIF.Mixin({
|
||||
dependencies: 'input',
|
||||
composition: {
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Get or set the checked state using jQuery's prop method
|
||||
component.value = value => {
|
||||
const isGet = _.isUndefined(value);
|
||||
if (isGet) {
|
||||
return component.parseData(component.$element.is(':checked'));
|
||||
}
|
||||
|
||||
component.$element.prop('checked', value);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,5 +1,8 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
/*
|
||||
* form: controls a form and its registered inputs
|
||||
@ -11,40 +14,83 @@ OHIF.mixins.form = new OHIF.Mixin({
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Define the form's data schema
|
||||
const schema = instance.data.schema;
|
||||
component.schema = schema && schema.newContext();
|
||||
// Set the form identifier flag
|
||||
component.isForm = true;
|
||||
|
||||
// Check if the form data is valid in its schema
|
||||
component.validationObserver = new Tracker.Dependency();
|
||||
|
||||
// Reset the pathKey
|
||||
instance.data.pathKey = '';
|
||||
|
||||
// Debound the observer call to prevent tons of re-rendering
|
||||
component.validationRan = _.debounce(() => {
|
||||
// Enable reactivity by changing a Tracker.Dependency observer
|
||||
component.validationObserver.changed();
|
||||
}, 200);
|
||||
|
||||
// Change the validation function to focus the fields with error
|
||||
const validateSelf = component.validate;
|
||||
component.validate = () => {
|
||||
// Assume validation result as true
|
||||
let result = true;
|
||||
// Call the original validation function
|
||||
validateSelf();
|
||||
|
||||
// Return true if there's no data schema defined
|
||||
if (!component.schema) {
|
||||
return result;
|
||||
// Focus the first error field if some validation failed
|
||||
if (component.schema && component.schema._invalidKeys.length) {
|
||||
instance.$('.state-error :input:first').focus();
|
||||
}
|
||||
|
||||
// Iterate over each registered form item and validate it
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
|
||||
// Change result to false if any form item is invalid
|
||||
if (key && !child.validate()) {
|
||||
result = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return the validation result
|
||||
return result;
|
||||
};
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the component main and style elements
|
||||
component.$style = component.$element = instance.$('form:first');
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .validation-error-container a'(event, instance) {
|
||||
// Get the target key
|
||||
const targetKey = $(event.currentTarget).attr('data-target');
|
||||
|
||||
// Focus the first input inside the element with error state
|
||||
instance.$(`.state-error[data-key="${targetKey}"] :input:first`).focus();
|
||||
}
|
||||
},
|
||||
|
||||
helpers: {
|
||||
validationErrors() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Create a dependency on child components validation
|
||||
component.validationObserver.depend();
|
||||
|
||||
// Stop here if no schema was defined for the form
|
||||
if (!component.schema) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there were some validation errors
|
||||
if (component.schema._invalidKeys.length) {
|
||||
const result = [];
|
||||
|
||||
// Iterate over each validation error and add to result
|
||||
component.schema._invalidKeys.forEach(item => {
|
||||
const label = component.schema._schema[item.name].label;
|
||||
let message = component.schema.keyErrorMessage(item.name);
|
||||
message = message.replace(label, `<strong>${label}</strong>`);
|
||||
result.push({
|
||||
key: item.name,
|
||||
message: Spacebars.SafeString(message)
|
||||
});
|
||||
});
|
||||
|
||||
// Return the resulting validation errors
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Tracker } from "meteor/tracker";
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
@ -31,7 +32,7 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
component.value = value => {
|
||||
const isGet = _.isUndefined(value);
|
||||
if (isGet) {
|
||||
return component.$element.val();
|
||||
return component.parseData(component.$element.val());
|
||||
}
|
||||
|
||||
component.$element.val(value).trigger('change');
|
||||
@ -53,6 +54,19 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
component.$wrapper[method]();
|
||||
};
|
||||
|
||||
// Check if the focus is inside this element
|
||||
component.hasFocus = () => {
|
||||
// Get the focused element
|
||||
const focused = $(':focus')[0];
|
||||
|
||||
// Check if the focused element is inside the component
|
||||
const contains = $.contains(component.$wrapper[0], focused);
|
||||
const isEqual = component.$wrapper[0] === focused;
|
||||
|
||||
// Return true if he component has the focus
|
||||
return contains || isEqual;
|
||||
};
|
||||
|
||||
// Add or remove a state from the component
|
||||
component.state = (state, flag) => {
|
||||
component.$wrapper.toggleClass(`state-${state}`, !!flag);
|
||||
@ -65,24 +79,77 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
|
||||
// Set or remove the error message
|
||||
if (errorMessage) {
|
||||
component.$element.trigger('errorin');
|
||||
component.$wrapper.attr('data-error', errorMessage);
|
||||
} else {
|
||||
component.$element.trigger('errorout');
|
||||
component.$wrapper.removeAttr('data-error', errorMessage);
|
||||
}
|
||||
};
|
||||
|
||||
// Toggle the tooltip over the component
|
||||
component.toggleTooltip = (isShow, message) => {
|
||||
if (isShow && message) {
|
||||
// Stop here if the tooltip is already created
|
||||
if (component.$wrapper.next('.tooltip').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the tooltip
|
||||
component.$wrapper.tooltip({
|
||||
trigger: 'manual',
|
||||
title: message
|
||||
}).tooltip('show');
|
||||
} else {
|
||||
// Destroy the tooltip
|
||||
component.$wrapper.tooltip('destroy');
|
||||
}
|
||||
};
|
||||
|
||||
// Toggle a state message as a tooltip over the component
|
||||
component.toggleMessage = isShow => {
|
||||
// Check if the action is to hide
|
||||
if (!isShow) {
|
||||
Meteor.setTimeout(() => {
|
||||
// Check if the component has the focus
|
||||
if (component.hasFocus()) {
|
||||
// Prevent the tooltip from being hidden
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide the tooltip
|
||||
component.toggleTooltip(false);
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for error state and message
|
||||
const errorMessage = component.$wrapper.attr('data-error');
|
||||
if (errorMessage) {
|
||||
// Show the tooltip with the error message
|
||||
component.toggleTooltip(true, errorMessage);
|
||||
}
|
||||
},
|
||||
|
||||
// Search for the parent form component
|
||||
component.getForm = () => {
|
||||
let currentComponent = component;
|
||||
while (currentComponent) {
|
||||
currentComponent = currentComponent.parent;
|
||||
if (currentComponent && currentComponent.isForm) {
|
||||
return currentComponent;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Check if the component value is valid in its form's schema
|
||||
component.validate = () => {
|
||||
// Get the component's form
|
||||
const form = component.parent;
|
||||
const form = component.getForm();
|
||||
|
||||
// Get the form's data schema
|
||||
const schema = form && form.schema;
|
||||
|
||||
// Get the current component's key
|
||||
const key = instance.data.key;
|
||||
const key = instance.data.pathKey;
|
||||
|
||||
// Return true if validation is not needed
|
||||
if (!key || !schema || !component.$wrapper.is(':visible')) {
|
||||
@ -90,12 +157,18 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
}
|
||||
|
||||
// Create the data document for validation
|
||||
const document = {
|
||||
const document = OHIF.blaze.getNestedObject({
|
||||
[key]: component.value()
|
||||
};
|
||||
});
|
||||
|
||||
// Get the validation result
|
||||
const validationResult = schema.validateOne(document, key);
|
||||
|
||||
// Notify the form that the validation ran
|
||||
form.validationRan();
|
||||
|
||||
// Check if the document validation failed
|
||||
if (!schema.validateOne(document, key)) {
|
||||
if (!validationResult) {
|
||||
// Set the component in error state and display the message
|
||||
component.error(schema.keyErrorMessage(key));
|
||||
|
||||
@ -125,6 +198,9 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
|
||||
// Set the most outer wrapper element
|
||||
component.$wrapper = instance.wrapper.$('*').first();
|
||||
|
||||
// Add the pathKey to the wrapper element
|
||||
component.$wrapper.attr('data-key', instance.data.pathKey);
|
||||
},
|
||||
|
||||
onDestroyed() {
|
||||
@ -143,24 +219,55 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
component.$style = component.$element;
|
||||
}
|
||||
|
||||
// Set the component in jQuery data after all mixins are rendered
|
||||
// Set the component in element and wrapper jQuery data
|
||||
component.$element.data('component', component);
|
||||
component.$wrapper.data('component', component);
|
||||
},
|
||||
|
||||
events: {
|
||||
|
||||
// Enable reactivity by changing a Tracker.Dependency observer
|
||||
// Handle the change event for the component
|
||||
change(event, instance) {
|
||||
instance.component.changeObserver.changed();
|
||||
const component = instance.component;
|
||||
|
||||
// Prevent execution on upper components
|
||||
if (event.currentTarget === component.$element[0]) {
|
||||
// Enable reactivity by changing a Tracker.Dependency observer
|
||||
component.changeObserver.changed();
|
||||
|
||||
// Revalidate the component
|
||||
component.validate();
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: [design] remove log, show error box/hint over the wrapper
|
||||
errorin(event, instance) {
|
||||
console.log('ERROR when validating component', instance.component);
|
||||
focus(event, instance) {
|
||||
const component = instance.component;
|
||||
|
||||
// Stop here if it is an group
|
||||
if (component.isGroup || component.isCustomFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent event bubbling
|
||||
event.stopPropagation();
|
||||
|
||||
// Check for state messages and show it
|
||||
component.toggleMessage(true);
|
||||
},
|
||||
|
||||
// TODO: [design] hide error box/hint
|
||||
errorout(event, instance) {
|
||||
blur(event, instance) {
|
||||
const component = instance.component;
|
||||
|
||||
// Stop here if it is an group
|
||||
if (component.isGroup || component.isCustomFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent event bubbling
|
||||
event.stopPropagation();
|
||||
|
||||
// Hide state messages
|
||||
component.toggleMessage(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,29 +12,124 @@ OHIF.mixins.group = new OHIF.Mixin({
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the group identifier flag
|
||||
component.isGroup = true;
|
||||
|
||||
// Run this computation every time the schema property is changed
|
||||
instance.autorun(() => {
|
||||
let schema = instance.data.schema;
|
||||
|
||||
// Check if the schema is reactive
|
||||
if (schema instanceof ReactiveVar) {
|
||||
// Register a dependency on schema property
|
||||
schema = schema.get();
|
||||
}
|
||||
|
||||
// Set the form's data schema
|
||||
component.schema = schema && schema.newContext();
|
||||
});
|
||||
|
||||
// Get or set the child components values
|
||||
component.value = value => {
|
||||
const isGet = _.isUndefined(value);
|
||||
const isArray = instance.data.arrayValues;
|
||||
|
||||
// Create the result data as array or object
|
||||
const result = isArray ? [] : {};
|
||||
|
||||
// Get the group current value and return it
|
||||
if (isGet) {
|
||||
const result = {};
|
||||
// Iterate over each registered item and extract its value
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
if (key) {
|
||||
result[key] = child.value();
|
||||
// Check if it is an array or an object group
|
||||
if (isArray) {
|
||||
// Push the item value to the result array
|
||||
result.push(child.value());
|
||||
} else {
|
||||
// Get the item key
|
||||
const key = child.templateInstance.data.key;
|
||||
|
||||
//Check if a key is set for the item
|
||||
if (key) {
|
||||
// Add the item value to the result object
|
||||
result[key] = child.value();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Return the resulting data as array or object
|
||||
return result;
|
||||
}
|
||||
|
||||
const groupValue = typeof value === 'object' ? value : {};
|
||||
// Get the group current value
|
||||
const groupValue = typeof value === 'object' ? value : result;
|
||||
|
||||
// Stop here if there is no value defined for this group
|
||||
if (!groupValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate over each registered item and set its value
|
||||
let i = 0;
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
const key = isArray ? i : child.templateInstance.data.key;
|
||||
const childValue = _.isUndefined(groupValue[key]) ? null : groupValue[key];
|
||||
child.value(childValue);
|
||||
i++;
|
||||
});
|
||||
|
||||
// Trigger the change event after setting the new value
|
||||
component.$element.trigger('change');
|
||||
};
|
||||
|
||||
// Get a registered item in form by its key
|
||||
component.item = itemKey => {
|
||||
let found;
|
||||
|
||||
// Iterate over each registered form item
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
|
||||
// Change the found item if current key is the same as given
|
||||
if (key === itemKey) {
|
||||
found = child;
|
||||
}
|
||||
});
|
||||
|
||||
// Return the found item or undefined if it was not found
|
||||
return found;
|
||||
};
|
||||
|
||||
// Check if the form data is valid in its schema
|
||||
const validateSelf = component.validate;
|
||||
component.validate = () => {
|
||||
// Assume validation result as true
|
||||
let result = true;
|
||||
|
||||
// Return true if there's no data schema defined
|
||||
if (component.isForm && !component.schema) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Validate the component itself if it has a key
|
||||
if (instance.data.pathKey && !validateSelf()) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Iterate over each registered form item and validate it
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
|
||||
// Change result to false if any form item is invalid
|
||||
if ((key || instance.data.arrayValues) && !child.validate()) {
|
||||
result = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return the validation result
|
||||
return result;
|
||||
};
|
||||
|
||||
// Disable or enable the component
|
||||
component.disable = isDisable => {
|
||||
component.registeredItems.forEach(child => child.disable(isDisable));
|
||||
|
||||
@ -21,7 +21,7 @@ OHIF.mixins.groupRadio = new OHIF.Mixin({
|
||||
component.registeredItems.forEach(child => elements.push(child.$element[0]));
|
||||
const $elements = $(elements);
|
||||
if (isGet) {
|
||||
return $elements.filter(':checked').val();
|
||||
return component.parseData($elements.filter(':checked').val());
|
||||
}
|
||||
|
||||
$elements.filter(`[value='${value}']`).prop('checked', true).trigger('change');
|
||||
|
||||
@ -7,7 +7,13 @@ import { _ } from 'meteor/underscore';
|
||||
// Helper function to get the component's current schema
|
||||
const getCurrentSchema = (parentComponent, key) => {
|
||||
// Get the parent component schema
|
||||
const schema = parentComponent && parentComponent.schema;
|
||||
let schema = parentComponent && parentComponent.schema;
|
||||
|
||||
// Try to get the form schema if it was not found
|
||||
if (parentComponent && !schema) {
|
||||
const form = parentComponent.getForm();
|
||||
schema = form && form.schema;
|
||||
}
|
||||
|
||||
// Stop here if there's no key or schema defined
|
||||
if (!key || !schema) {
|
||||
@ -17,6 +23,11 @@ const getCurrentSchema = (parentComponent, key) => {
|
||||
// Get the current schema data using component's key
|
||||
const currentSchema = _.clone(schema._schema[key]);
|
||||
|
||||
// Stop here if no schema was found for the given key
|
||||
if (!currentSchema) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge the sub-schema properties if it's an array
|
||||
if (Array.isArray(currentSchema.type())) {
|
||||
_.extend(currentSchema, schema._schema[key + '.$']);
|
||||
@ -40,8 +51,21 @@ OHIF.mixins.schemaData = new OHIF.Mixin({
|
||||
// Get the parent component
|
||||
const parent = OHIF.blaze.getParentComponent(Blaze.currentView);
|
||||
|
||||
// Get he parent component key
|
||||
const parentKey = parent && parent.templateInstance.data.pathKey;
|
||||
|
||||
// Check if the parent is an array group
|
||||
const isParentArray = parent && parent.templateInstance.data.arrayValues;
|
||||
|
||||
// Set the path key for this component
|
||||
data.pathKey = data.key || (isParentArray ? '$' : '');
|
||||
if (data.pathKey && typeof parentKey === 'string') {
|
||||
const prefix = parentKey ? `${parentKey}.` : '';
|
||||
data.pathKey = `${prefix}${data.pathKey}`;
|
||||
}
|
||||
|
||||
// Get the current schema data using component's key
|
||||
const currentSchema = getCurrentSchema(parent, data.key);
|
||||
const currentSchema = getCurrentSchema(parent, data.pathKey);
|
||||
|
||||
// Stop here if there's no schema data for current key
|
||||
if (!currentSchema) {
|
||||
@ -53,6 +77,11 @@ OHIF.mixins.schemaData = new OHIF.Mixin({
|
||||
data.label = new ReactiveVar(currentSchema.label);
|
||||
}
|
||||
|
||||
// Set the emptyOption data attribute if given on schema
|
||||
if (currentSchema.emptyOption) {
|
||||
data.emptyOption = currentSchema.emptyOption;
|
||||
}
|
||||
|
||||
// Fill the items if it's an array schema
|
||||
if (!data.items && Array.isArray(currentSchema.allowedValues)) {
|
||||
// Initialize the items array
|
||||
@ -76,12 +105,41 @@ OHIF.mixins.schemaData = new OHIF.Mixin({
|
||||
}
|
||||
},
|
||||
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Create a data parser according to current schema key
|
||||
component.parseData = value => {
|
||||
// Get the current schema data using component's key
|
||||
const currentSchema = getCurrentSchema(component.parent, instance.data.pathKey);
|
||||
|
||||
// Stop here if there's no schema data for current key
|
||||
if (!currentSchema) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the schema is a Number
|
||||
if (currentSchema.type === Number) {
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
// Check if the schema is a Boolean
|
||||
if (currentSchema.type === Boolean) {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
// Return the original value if none of the checks matched
|
||||
return value;
|
||||
};
|
||||
},
|
||||
|
||||
onMixins() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Get the current schema data using component's key
|
||||
const currentSchema = getCurrentSchema(component.parent, instance.data.key);
|
||||
const currentSchema = getCurrentSchema(component.parent, instance.data.pathKey);
|
||||
|
||||
// Stop here if there's no schema data for current key
|
||||
if (!currentSchema) {
|
||||
|
||||
@ -8,6 +8,46 @@ import { $ } from 'meteor/jquery';
|
||||
OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
dependencies: 'select',
|
||||
composition: {
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Set the custom focus flag
|
||||
instance.component.isCustomFocus = true;
|
||||
|
||||
// Check if this select will include a placeholder
|
||||
const placeholder = instance.data.options && instance.data.options.placeholder;
|
||||
if (placeholder) {
|
||||
// Get the option items
|
||||
let items = instance.data.items;
|
||||
|
||||
// Check if the items are reactive and get them if true
|
||||
const isReactive = items instanceof ReactiveVar;
|
||||
if (isReactive) {
|
||||
items = items.get();
|
||||
}
|
||||
|
||||
// Check if there is already an empty option on items list
|
||||
const query = {
|
||||
value: ''
|
||||
};
|
||||
if (!_.findWhere(items, query)) {
|
||||
// Clone the current items
|
||||
const newItems = _.clone(items) || [];
|
||||
newItems.unshift({
|
||||
label: placeholder,
|
||||
value: ''
|
||||
});
|
||||
|
||||
// Set the new items list including the empty option
|
||||
if (isReactive) {
|
||||
instance.data.items.set(newItems);
|
||||
} else {
|
||||
instance.data.items = newItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
@ -17,6 +57,22 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
|
||||
// Store the select2 instance to allow its further destruction
|
||||
component.select2Instance = component.$element.data('select2');
|
||||
|
||||
// Get the focusable elements
|
||||
const elements = [];
|
||||
elements.push(component.$element[0]);
|
||||
elements.push(component.$element.nextAll('.select2:first').find('.select2-selection')[0]);
|
||||
|
||||
// Attach focus and blur handlers to focusable elements
|
||||
$(elements).on('focus', event => {
|
||||
event.stopPropagation();
|
||||
// Show the state message on elements focus
|
||||
component.toggleMessage(true);
|
||||
}).on('blur', event => {
|
||||
event.stopPropagation();
|
||||
// Hide the state message on elements blur
|
||||
component.toggleMessage(false);
|
||||
});
|
||||
},
|
||||
|
||||
onDestroyed() {
|
||||
@ -25,14 +81,6 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
|
||||
// Destroy the select2 instance to remove unwanted DOM elements
|
||||
component.select2Instance.destroy();
|
||||
},
|
||||
|
||||
events: {
|
||||
'focus .select2-hidden-accessible'(event, instance) {
|
||||
// Redirect the focus to select2 focus control in case of hidden
|
||||
// accessible being focused (e.g. clicking on outer label)
|
||||
$(event.currentTarget).nextAll('.select2:first').find('.select2-selection').focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -30,7 +30,7 @@ OHIF.mixins.selectTree = new OHIF.Mixin({
|
||||
|
||||
// Return the current value
|
||||
if (isGet) {
|
||||
return rootInstance.currentValue;
|
||||
return component.parseData(rootInstance.currentValue);
|
||||
}
|
||||
|
||||
// Change the current value
|
||||
|
||||
@ -11,6 +11,13 @@
|
||||
target="{{this.target}}"
|
||||
{{this.tagAttributes}}
|
||||
>
|
||||
{{#if validationErrors}}
|
||||
<div class="validation-error-container alert alert-danger" role="alert">
|
||||
{{#each error in validationErrors}}
|
||||
<p><a href="#" class="text-danger" data-target="{{error.key}}">{{error.message}}</a></p>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{>UI.contentBlock}}
|
||||
</form>
|
||||
</template>
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
class="{{this.class}}"
|
||||
name="{{this.name}}"
|
||||
multiple="{{#if this.multiple}}multiple{{/if}}"
|
||||
disabled="{{#if this.disabled}}disabled{{/if}}"
|
||||
{{this.tagAttributes}}
|
||||
>
|
||||
{{>UI.contentBlock}}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import './form/form.html';
|
||||
import './form/group.html';
|
||||
|
||||
import './input/checkbox.html';
|
||||
import './input/hidden.html';
|
||||
import './input/groupRadio.html';
|
||||
import './input/radio.html';
|
||||
import './input/select.html';
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
<template name="inputCheckbox">
|
||||
{{#baseComponent (extend this
|
||||
base='baseInput'
|
||||
type='checkbox'
|
||||
mixins=(concat 'checkbox ' this.mixins)
|
||||
labelAfter=(valueIf (isUndefined this.labelAfter) true this.labelAfter)
|
||||
labelClass=(concat 'checkboxLabel ' this.labelClass)
|
||||
wrappers=(concat ''
|
||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||
this.wrappers
|
||||
)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/baseComponent}}
|
||||
</template>
|
||||
@ -0,0 +1,7 @@
|
||||
<template name="inputHidden">
|
||||
{{>baseComponent (extend this
|
||||
base='baseInput'
|
||||
type='hidden'
|
||||
mixins=(concat 'input ' this.mixins)
|
||||
)}}
|
||||
</template>
|
||||
@ -4,7 +4,7 @@
|
||||
type='radio'
|
||||
mixins=(concat 'input ' this.mixins)
|
||||
labelAfter=(valueIf (isUndefined this.labelAfter) true this.labelAfter)
|
||||
labelClass=(concat 'checkboxLabel ' this.labelClass)
|
||||
labelClass=(concat 'radioLabel ' this.labelClass)
|
||||
wrappers=(concat ''
|
||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||
this.wrappers
|
||||
|
||||
@ -11,17 +11,19 @@
|
||||
<div class="tree-content">
|
||||
{{#let currentNode=this.currentNode.get}}
|
||||
{{#if (and (not this.root) (ne this.search false))}}
|
||||
{{>inputText
|
||||
{{#inputText
|
||||
label=this.label
|
||||
labelClass='tree-search'
|
||||
placeholder=(choose this.searchPlaceholder 'Search')
|
||||
}}
|
||||
<i class="fa fa-search"></i>
|
||||
{{/inputText}}
|
||||
{{/if}}
|
||||
<div class="tree-options {{#if currentNode}}collapsed{{/if}}">
|
||||
{{#if this.root}}
|
||||
{{>selectTreeBreadcrumb component=this.component}}
|
||||
{{/if}}
|
||||
<div class="tree-inputs">
|
||||
<div class="tree-inputs clearfix">
|
||||
{{#each item in treeItems}}
|
||||
{{>inputRadio
|
||||
id=(concat this.storageKey '_' (encodeId item.value))
|
||||
@ -45,8 +47,8 @@
|
||||
</div>
|
||||
{{/let}}
|
||||
</div>
|
||||
{{#if (and (not this.root) this.storageKey)}}
|
||||
{{>selectTreeCommon (clone this component=this.component)}}
|
||||
{{#if (and (not this.root) (or this.storageKey this.commonItems))}}
|
||||
{{>selectTreeCommon (clone this component=this.component treeInstance=instance)}}
|
||||
{{/if}}
|
||||
{{/group}}
|
||||
</template>
|
||||
|
||||
@ -11,6 +11,45 @@ import transition from 'meteor/ohif:core/client/lib/third-party/transition-to-fr
|
||||
Template.selectTree.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Return the common items
|
||||
instance.getCommonItems = () => {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Return the common items if given
|
||||
if (instance.data.commonItems) {
|
||||
return instance.data.commonItems;
|
||||
}
|
||||
|
||||
// Get all the tree leaves
|
||||
const leaves = instance.data.component.getLeaves();
|
||||
|
||||
// Generate an object with encoded keys from the tree leaves
|
||||
leavesObject = {};
|
||||
_.each(leaves, leaf => {
|
||||
leavesObject[OHIF.string.encodeId(leaf.value)] = leaf;
|
||||
});
|
||||
|
||||
// Get the current items ranking
|
||||
const ranking = OHIF.user.getData(instance.data.storageKey);
|
||||
|
||||
// Sort the items based on how many times each one was used
|
||||
const sorted = [];
|
||||
_.each(ranking, (count, key) => sorted.push([key, count]));
|
||||
sorted.sort((a, b) => b[1] - a[1]);
|
||||
|
||||
// Create the result and push every item respecting the ranking order
|
||||
const result = [];
|
||||
_.each(sorted, item => {
|
||||
const current = leavesObject[item[0]];
|
||||
if (current) {
|
||||
result.push(current);
|
||||
}
|
||||
});
|
||||
|
||||
// Return the resulting array
|
||||
return result;
|
||||
};
|
||||
|
||||
// Create a reactive variable to control the search
|
||||
instance.searchTerm = new ReactiveVar('');
|
||||
});
|
||||
@ -25,7 +64,10 @@ Template.selectTree.onRendered(() => {
|
||||
instance.component = component;
|
||||
|
||||
// Set the margin to display the common section
|
||||
$treeRoot.children('.tree-content').css('margin-right', $treeRoot.width());
|
||||
const isTreeColumns = instance.data.treeColumns;
|
||||
const marginProperty = isTreeColumns ? 'margin-left' : 'margin-right';
|
||||
const marginWidth = isTreeColumns ? $treeRoot.width() / 2 : $treeRoot.width();
|
||||
$treeRoot.children('.tree-content').css(marginProperty, marginWidth);
|
||||
|
||||
// Make the component respect the window boundaries
|
||||
$treeRoot.bounded();
|
||||
@ -144,6 +186,18 @@ Template.selectTree.events({
|
||||
$treeRoot.addClass('interacted');
|
||||
},
|
||||
|
||||
'keydown .tree-search input'(event, instance) {
|
||||
// Get the search term
|
||||
const searchTerm = $(event.currentTarget).val().trim();
|
||||
|
||||
const $labels = instance.$('.tree-inputs:first>label');
|
||||
|
||||
// Select the label if ENTER was pressed and there is only one result
|
||||
if (searchTerm.length && $labels.length === 1 && event.which === 13) {
|
||||
$labels.find('input').click();
|
||||
}
|
||||
},
|
||||
|
||||
'change .select-tree:first>.tree-content>.tree-options>.tree-inputs>label>input'(event, instance) {
|
||||
const component = instance.component;
|
||||
const $target = $(event.currentTarget);
|
||||
@ -235,27 +289,6 @@ Template.selectTree.events({
|
||||
currentInstance = currentInstance.component.parent.templateInstance;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'click .select-tree-common label'(event, instance) {
|
||||
// Get the clicked label
|
||||
const $target = $(event.currentTarget);
|
||||
|
||||
// Build the input selector based on the label target
|
||||
const inputSelector = '#' + $target.attr('for');
|
||||
|
||||
// Check if the input is not rendered
|
||||
if (!$(inputSelector).length) {
|
||||
// Change the search terms with the clicked label string
|
||||
|
||||
instance.$('.tree-search input').val($target.text()).trigger('input');
|
||||
// Wait for options rerendering
|
||||
|
||||
Tracker.afterFlush(() => {
|
||||
// Wait for components initialization
|
||||
Meteor.defer(() => $(inputSelector).click());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -276,6 +309,23 @@ Template.selectTree.helpers({
|
||||
|
||||
// Filter only the tree leaves
|
||||
items = _.filter(items, item => !item.items);
|
||||
} else if (instance.data.hideCommon) {
|
||||
// Get the values of common items
|
||||
const commonValues = _.pluck(instance.getCommonItems(), 'value');
|
||||
|
||||
// Filter only the items that are not common
|
||||
items = _.filter(items, item => !_.contains(commonValues, item.value));
|
||||
}
|
||||
|
||||
// Return the items sorted for tree columns
|
||||
if (instance.data.treeColumns) {
|
||||
const begin = items.splice(0, Math.ceil(items.length / 2));
|
||||
const sortedItems = [];
|
||||
_.each(begin, (item, index) => {
|
||||
sortedItems.push(item);
|
||||
items[index] && sortedItems.push(items[index]);
|
||||
});
|
||||
items = sortedItems;
|
||||
}
|
||||
|
||||
// Return the tree items
|
||||
|
||||
@ -2,38 +2,35 @@ import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
Template.selectTreeCommon.helpers({
|
||||
// Get the common items ordered by use history
|
||||
items() {
|
||||
const instance = Template.instance();
|
||||
Template.selectTreeCommon.events({
|
||||
'click .select-tree-common label'(event, instance) {
|
||||
// Get the clicked label
|
||||
const $target = $(event.currentTarget);
|
||||
|
||||
// Get all the tree leaves
|
||||
const leaves = instance.data.component.getLeaves();
|
||||
// Build the input selector based on the label target
|
||||
const inputSelector = '#' + $target.attr('for');
|
||||
|
||||
// Generate an object with encoded keys from the tree leaves
|
||||
leavesObject = {};
|
||||
_.each(leaves, leaf => {
|
||||
leavesObject[OHIF.string.encodeId(leaf.value)] = leaf;
|
||||
});
|
||||
// Get the tree instance
|
||||
const treeInstance = instance.data.treeInstance;
|
||||
|
||||
// Get the current items ranking
|
||||
const ranking = OHIF.user.getData(instance.data.storageKey);
|
||||
// Check if the input is not rendered
|
||||
if (!$(inputSelector).length) {
|
||||
// Change the search terms with the clicked label string
|
||||
|
||||
// Sort the items based on how many times each one was used
|
||||
const sorted = [];
|
||||
_.each(ranking, (count, key) => sorted.push([key, count]));
|
||||
sorted.sort((a, b) => b[1] - a[1]);
|
||||
treeInstance.$('.tree-search input').val($target.text()).trigger('input');
|
||||
// Wait for options rerendering
|
||||
|
||||
// Create the result and push every item respecting the ranking order
|
||||
const result = [];
|
||||
_.each(sorted, item => {
|
||||
const current = leavesObject[item[0]];
|
||||
if (current) {
|
||||
result.push(current);
|
||||
}
|
||||
});
|
||||
|
||||
// Return the resulting array
|
||||
return result;
|
||||
Tracker.afterFlush(() => {
|
||||
// Wait for components initialization
|
||||
Meteor.defer(() => $(inputSelector).click());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.selectTreeCommon.helpers({
|
||||
// Get the common items
|
||||
items() {
|
||||
return Template.instance().data.treeInstance.getCommonItems();
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template name="componentPlayground">
|
||||
<div class="component-playground">
|
||||
{{>measureFlow}}
|
||||
{{>measureFlow treeColumns=true hideCommon=true}}
|
||||
<!--
|
||||
<div class="p-a-3">
|
||||
{{>selectTree
|
||||
|
||||
@ -31,7 +31,7 @@ OHIF.blaze.getParentView = (view, parentViewName) => {
|
||||
};
|
||||
|
||||
// Search for the parent component of the given view
|
||||
OHIF.blaze.getParentComponent = (view) => {
|
||||
OHIF.blaze.getParentComponent = view => {
|
||||
let currentView = view;
|
||||
while (currentView) {
|
||||
currentView = currentView.originalParentView || currentView.parentView;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import './blaze.js';
|
||||
import './object.js';
|
||||
import './string.js';
|
||||
import './ui.js';
|
||||
import './user.js';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user